Przeglądaj źródła

Merge pull request #157 from bmx-ng/bcc_externs

Better extern functionality
Brucey 9 lat temu
rodzic
commit
fb52c0c7f8
8 zmienionych plików z 663 dodań i 229 usunięć
  1. 349 121
      ctranslator.bmx
  2. 85 16
      decl.bmx
  3. 34 11
      expr.bmx
  4. 70 6
      iparser.bmx
  5. 100 72
      parser.bmx
  6. 9 1
      stmt.bmx
  7. 1 1
      toker.bmx
  8. 15 1
      type.bmx

+ 349 - 121
ctranslator.bmx

@@ -82,7 +82,19 @@ Type TCTranslator Extends TTranslator
 			s:+ TransArrayType(TArrayType( ty ).elemType)
 			Return Enquote(s.Replace("~q", ""))
 		End If
-		If TObjectType( ty ) Return "~q:" + TObjectType(ty).classDecl.ident + "~q"
+		If TObjectType( ty ) Then
+			If Not TObjectType( ty ).classdecl.IsExtern()
+				Return "~q:" + TObjectType(ty).classDecl.ident + "~q"
+			Else
+				If TObjectType( ty ).classdecl.IsInterface() Then
+					Return "~q" + p + "*#" + TObjectType(ty).classDecl.ident + "~q"
+				ElseIf TObjectType( ty ).classdecl.IsStruct()
+					Return "~q" + p + "@" + TObjectType(ty).classDecl.ident + "~q"
+				Else
+					Return "~q" + p + "#" + TObjectType(ty).classDecl.ident + "~q"
+				End If
+			End If
+		End If
 		If TFunctionPtrType( ty ) Return "~q(~q"
 
 	End Method
@@ -148,7 +160,17 @@ Type TCTranslator Extends TTranslator
 			Return s + TransDebugScopeType(TArrayType( ty ).elemType)
 		End If
 		If TObjectType( ty ) Then
-			Return ":" + TObjectType( ty ).classDecl.ident
+			If Not TObjectType( ty ).classdecl.IsExtern()
+				Return ":" + TObjectType( ty ).classDecl.ident
+			Else
+				If TObjectType( ty ).classdecl.IsInterface() Then
+					Return p + "*#" + TObjectType(ty).classDecl.ident
+				ElseIf TObjectType( ty ).classdecl.IsStruct() Then
+					Return p + "@" + TObjectType(ty).classDecl.ident
+				Else
+					Return p + "#" + TObjectType(ty).classDecl.ident
+				End If
+			End If
 		End If
 		If TFunctionPtrType( ty ) Then
 			Local func:TFuncDecl = TFunctionPtrType( ty ).func
@@ -256,14 +278,25 @@ Type TCTranslator Extends TTranslator
 			Next
 			Return s + "]"
 		End If
-		If TObjectType( ty ) Return ":" + TObjectType(ty).classDecl.ident + p
+		If TObjectType( ty ) Then
+			Local t:String = ":"
+			If TObjectType(ty).classDecl.IsExtern() Then
+				If TObjectType(ty).classDecl.IsInterface() Then
+					t = "??"
+				ElseIf TObjectType(ty).classDecl.IsStruct() Then
+					t = "~~"
+				Else
+					t = "?"
+				End If
+			End If
+			Return t + TObjectType(ty).classDecl.ident + p
+		End If
 		If TFunctionPtrType( ty ) Return TransIfcType(TFunctionPtrType(ty).func.retType) + TransIfcArgs(TFunctionPtrType(ty).func)
 		If TExternObjectType( ty ) Return ":" + TExternObjectType(ty).classDecl.ident + p
 		InternalErr
 	End Method
 
 	Method TransRefType$( ty:TType, ident:String )
-		If TObjectType( ty ) And ty.GetClass().IsInterface() Return "gc_iptr<"+ty.GetClass().actual.munged+">"
 		Return TransType( ty, ident )
 	End Method
 
@@ -324,7 +357,11 @@ Type TCTranslator Extends TTranslator
 			If TArrayType( ty ) Return "&bbEmptyArray"
 			If TObjectType( ty ) Then
 				If TObjectType( ty ).classDecl.IsExtern() Then
-					Return "0"
+					If TObjectType( ty ).classDecl.IsInterface() Or IsPointerType(ty) Or (Not TObjectType( ty ).classDecl.IsStruct()) Then
+						Return "0"
+					Else
+						Return "{}"
+					End If
 				Else
 					Return "&bbNullObject"
 				End If
@@ -336,8 +373,9 @@ Type TCTranslator Extends TTranslator
 	
 	Method TransArgs$( args:TExpr[],decl:TFuncDecl, objParam:String = Null )
 'If decl.ident="ToHex" DebugStop
+
 		Local t$
-		If objParam And decl.IsMethod() Then
+		If objParam And decl.IsMethod() And ((Not decl.IsExtern()) Or (decl.IsExtern() And TClassDecl(decl.scope) And Not TClassDecl(decl.scope).IsStruct())) Then
 			t:+ objParam
 		End If
 		For Local i:Int=0 Until decl.argDecls.Length
@@ -569,7 +607,15 @@ t:+"NULLNULLNULL"
 					ty = init.exprType
 				End If
 				If TObjectType(ty) Then
-					Return TransType( ty, decl.munged )+" volatile "+decl.munged+"="+init.Trans()
+					If TObjectType(ty).classdecl.IsExtern() Then
+						If TObjectType(ty).classdecl.IsInterface() Then
+							Return TransType( ty, decl.munged )+" "+decl.munged+"="+init.Trans()
+						Else
+							Return TransType( ty, decl.munged )+" "+decl.munged+"="+init.Trans()
+						End If
+					Else
+						Return TransType( ty, decl.munged )+" volatile "+decl.munged+"="+init.Trans()
+					End If
 				Else
 					Return TransType( ty, decl.munged )+" "+decl.munged+"="+init.Trans()
 				End If
@@ -582,7 +628,15 @@ t:+"NULLNULLNULL"
 			Return TransType( decl.ty, decl.munged ) + "=" + TransValue(decl.ty, "")
 		Else
 			If TObjectType(decl.ty) Then
-				Return TransType( decl.ty, decl.munged )+" volatile "+decl.munged + "=" + TransValue(decl.ty, "")
+				If TObjectType(decl.ty).classdecl.IsExtern() Then
+					If Not TObjectType(decl.ty).classdecl.IsStruct() Then
+						Return TransType( decl.ty, decl.munged )+" "+decl.munged+"=" + TransValue(decl.ty, "")
+					Else
+						Return TransType( decl.ty, decl.munged )+" "+decl.munged
+					End If
+				Else
+					Return TransType( decl.ty, decl.munged )+" volatile "+decl.munged + "=" + TransValue(decl.ty, "")
+				End If
 			Else
 				Return TransType( decl.ty, decl.munged )+" "+decl.munged + "=" + TransValue(decl.ty, "")
 			End If
@@ -747,7 +801,7 @@ t:+"NULLNULLNULL"
 		If sup Then
 			tSuper = "->super"
 		End If
-		
+
 		If Not decl.munged
 			MungDecl decl
 		End If
@@ -776,7 +830,11 @@ t:+"NULLNULLNULL"
 						Return TransSubExpr( lhs ) + "->" + decl.munged+TransArgs( args,decl, Null)
 					Else
 						If decl.scope.IsExtern()
-							Return decl.munged + Bra(TransArgs( args,decl, TransSubExpr( lhs ) ))
+							If Not cdecl.IsStruct()  Then
+								'Return decl.munged + Bra(TransArgs( args,decl, TransSubExpr( lhs ) ))
+								Return TransSubExpr( lhs ) + "->vtbl->" + decl.munged + Bra(TransArgs( args,decl, TransSubExpr( lhs ) ))
+							End If
+							Err "TODO extern types not allowed methods"
 						Else
 							If cdecl.IsInterface() And reserved_methods.Find("," + decl.IdentLower() + ",") = -1 Then
 								Local ifc:String = Bra("(struct " + cdecl.munged + "_methods*)" + Bra("bbObjectInterface(" + TransSubExpr( lhs ) + ", " + "&" + cdecl.munged + "_ifc)"))
@@ -815,7 +873,11 @@ t:+"NULLNULLNULL"
 					Local obj:String = Bra(TransObject(cdecl))
 					
 					If decl.scope.IsExtern()
-						Return decl.munged + Bra(TransArgs( args,decl, TransSubExpr( lhs ) ))
+						If TClassDecl(decl.scope) And Not TClassDecl(decl.scope).IsStruct() Then
+							Return TransSubExpr( lhs ) + "->vtbl->" + decl.munged + Bra(TransArgs( args,decl, TransSubExpr( lhs ) ))
+						Else
+							Return decl.munged + Bra(TransArgs( args,decl, TransSubExpr( lhs ) ))
+						End If
 					Else
 						' Null test
 						If opt_debug Then
@@ -847,14 +909,22 @@ t:+"NULLNULLNULL"
 					' create a local variable of the inner invocation
 					Local lvar:String = CreateLocal(lhs)
 
-					' Null test
-					If opt_debug Then
-						EmitDebugNullObjectError(lvar)
+					If decl.scope.IsExtern()
+						If TClassDecl(decl.scope) And Not TClassDecl(decl.scope).IsStruct() Then
+							Return lvar + "->vtbl->" + decl.munged + Bra(TransArgs( args,decl, lvar ))
+						End If
+						
+						Return "// TODO"
+					Else
+						' Null test
+						If opt_debug Then
+							EmitDebugNullObjectError(lvar)
+						End If
+	
+						Local obj:String = lvar + "->clas" + tSuper
+						Return obj + "->" + TransFuncPrefix(decl.scope, decl)+ decl.ident+TransArgs( args,decl, lvar )
 					End If
 
-					Local obj:String = lvar + "->clas" + tSuper
-					Return obj + "->" + TransFuncPrefix(decl.scope, decl)+ decl.ident+TransArgs( args,decl, lvar )
-
 				Else If TIndexExpr(lhs) Then
 					Local loc:String = CreateLocal(lhs)
 					Local obj:String = Bra(TransObject(decl.scope))
@@ -920,7 +990,11 @@ t:+"NULLNULLNULL"
 			Return "BBOBJECT"
 		Else
 			If decl.IsExtern() Then
-				Return "struct " + decl.munged + "_ext*"
+				If Not TClassDecl(decl).IsStruct() Then
+					Return "struct " + decl.ident + "*"
+				Else
+					Return "struct " + decl.ident
+				End If
 			Else
 				Return "struct " + decl.munged + "_obj*"
 			End If
@@ -1171,7 +1245,11 @@ t:+"NULLNULLNULL"
 	Method TransNewArrayExpr$( expr:TNewArrayExpr )
 
 		If expr.expr.length = 1 Then
-			Return "bbArrayNew1D" + Bra(TransArrayType(expr.ty) + ", " + expr.expr[0].Trans())
+			If TObjectType(expr.ty) And TObjectType(expr.ty).classdecl.IsExtern() And TObjectType(expr.ty).classdecl.IsStruct() And Not IsPointerType(expr.ty) Then
+				Return "bbArrayNew1DStruct" + Bra(TransArrayType(expr.ty) + ", " + expr.expr[0].Trans() + ", sizeof" + Bra(TransObject(TObjectType(expr.ty).classdecl)))
+			Else
+				Return "bbArrayNew1D" + Bra(TransArrayType(expr.ty) + ", " + expr.expr[0].Trans())
+			End If
 		Else
 			' multiple array
 			Local s:String
@@ -1323,7 +1401,17 @@ t:+"NULLNULLNULL"
 			If TDoubleType( src ) Return Bra( t+"!=0.0f" )
 			If TArrayType( src ) Return Bra( t+"!= &bbEmptyArray" )
 			If TStringType( src ) Return Bra( t+"!= &bbEmptyString" )
-			If TObjectType( src ) Return Bra( t+"!= &bbNullObject" )
+			If TObjectType( src ) Then
+				If TObjectType(src).classDecl.IsExtern() Then
+					If Not TObjectType(src).classDecl.IsStruct() Then
+						Return Bra( t+"!=0" )
+					Else
+						Return Bra("1")
+					End If
+				Else
+					Return Bra( t+"!= &bbNullObject" )
+				End If
+			End If
 		Else If TIntType( dst )
 			If TBoolType( src ) Return Bra( t )
 			If TByteType( src) Return Bra("(BBINT)"+t)
@@ -1499,15 +1587,23 @@ t:+"NULLNULLNULL"
 			'If TArrayType( src ) Return Bra("(BBOBJECT)"+t)
 			'If TStringType( src ) Return Bra("(BBOBJECT)"+t)
 			'If TObjectType( src ) Return t
-			If TNullType( src ) Return "&bbNullObject"
-			If TObjectType(dst).classDecl.IsInterface() Then
-				Return Bra(Bra(TransObject(TObjectType(dst).classDecl)) + "bbInterfaceDowncast" + Bra(t + ",&" + TObjectType(dst).classDecl.munged + "_ifc"))
+			If Not TObjectType( dst ).classDecl.IsExtern() Then
+				If TNullType( src ) Return "&bbNullObject"
+				If TObjectType(dst).classDecl.IsInterface() Then
+					Return Bra(Bra(TransObject(TObjectType(dst).classDecl)) + "bbInterfaceDowncast" + Bra(t + ",&" + TObjectType(dst).classDecl.munged + "_ifc"))
+				Else
+					' no need to downcast to BBObject, as all objects extend it...
+					If TObjectType( dst ).classDecl.ident = "Object" Then
+						Return t
+					Else
+						Return Bra(Bra(TransObject(TObjectType(dst).classDecl)) + "bbObjectDowncast" + Bra(t + ",&" + TObjectType(dst).classDecl.munged))
+					End If
+				End If
 			Else
-				' no need to downcast to BBObject, as all objects extend it...
-				If TObjectType( dst ).classDecl.ident = "Object" Then
+				If TObjectType( dst ).classDecl.IsInterface() Then
 					Return t
 				Else
-					Return Bra(Bra(TransObject(TObjectType(dst).classDecl)) + "bbObjectDowncast" + Bra(t + ",&" + TObjectType(dst).classDecl.munged))
+					Return "" ' TODO??
 				End If
 			End If
 		End If
@@ -1966,9 +2062,6 @@ t:+"NULLNULLNULL"
 
 		Local s:String
 
-'		If ObjectType( stmt.rhs.exprType )
-'			If stmt.rhs.exprType.GetClass().IsInterface() rhs="GC_IPTR"+Bra(rhs)
-'		Endif
 		If IsPointerType(stmt.lhs.exprType, TType.T_BYTE) And rhs = "&bbNullObject" Then
 			rhs = "0"
 		End If
@@ -2320,6 +2413,11 @@ End Rem
 
 	Method EmitFuncDecl( decl:TFuncDecl, proto:Int = False, classFunc:Int = False )
 		'If Not proto And decl.IsAbstract() Return
+		
+		Local tmpDebug:Int = opt_debug
+		If decl.isNoDebug() Then
+			opt_debug = False
+		End If
 
 		'PushMungScope
 		BeginLocalScope
@@ -2474,6 +2572,9 @@ End Rem
 
 		EndLocalScope
 		'PopMungScope
+		
+		opt_debug = tmpDebug
+		
 	End Method
 	
 	Method EmitLocalDeclarations(decl:TScopeDecl, ignoreVar:TValDecl = Null)
@@ -2499,9 +2600,17 @@ End Rem
 			decl.Semant()
 
 			If Not TFunctionPtrType(decl.ty) Then
-				Emit TransType(decl.ty, classDecl.actual.munged) + " _" + classDecl.actual.munged.ToLower() + "_" + decl.IdentLower() + ";"
+				If classDecl.IsExtern() Then
+					Emit TransType(decl.ty, "") + " " + decl.ident + ";"
+				Else
+					Emit TransType(decl.ty, classDecl.actual.munged) + " _" + classDecl.actual.munged.ToLower() + "_" + decl.IdentLower() + ";"
+				End If
 			Else
-				Emit TransType(decl.ty, "_" + classDecl.actual.munged.ToLower() + "_" + decl.IdentLower()) + ";"
+				If classDecl.IsExtern() Then
+					Emit TransType(decl.ty, decl.ident) + ";"
+				Else
+					Emit TransType(decl.ty, "_" + classDecl.actual.munged.ToLower() + "_" + decl.IdentLower()) + ";"
+				End If
 			End If
 		Next
 
@@ -2591,119 +2700,208 @@ End Rem
 			superid=classDecl.superClass.actual.munged
 		End If
 
-		If Not classDecl.IsExtern() Then
-			Emit "void _" + classid + "_New" + Bra(TransObject(classdecl) + " o") + ";"
-			
-			If classHierarchyHasFunction(classDecl, "Delete") Then
-				Emit "void _" + classid + "_Delete" + Bra(TransObject(classdecl) + " o") + ";"
-			End If
-
-			If classHasFunction(classDecl, "ToString") Then
-				Emit "BBSTRING _" + classid + "_ToString" + Bra(TransObject(classdecl) + " o") + ";"
-			End If
+		Emit "void _" + classid + "_New" + Bra(TransObject(classdecl) + " o") + ";"
+		
+		If classHierarchyHasFunction(classDecl, "Delete") Then
+			Emit "void _" + classid + "_Delete" + Bra(TransObject(classdecl) + " o") + ";"
+		End If
 
-			If classHasFunction(classDecl, "Compare") Then
-				Emit "BBINT _" + classid + "_Compare(" + TransObject(classdecl) + " o, BBOBJECT otherObject);"
-			End If
+		If classHasFunction(classDecl, "ToString") Then
+			Emit "BBSTRING _" + classid + "_ToString" + Bra(TransObject(classdecl) + " o") + ";"
+		End If
 
-			If classHasFunction(classDecl, "SendMessage") Then
-				Emit "void _" + classid + "_SendMessage(BBOBJECT o, BBOBJECT message, BBOBJECT source);"
-			End If
+		If classHasFunction(classDecl, "Compare") Then
+			Emit "BBINT _" + classid + "_Compare(" + TransObject(classdecl) + " o, BBOBJECT otherObject);"
+		End If
 
-			Local reserved:String = ",New,Delete,ToString,Compare,SendMessage,_reserved1_,_reserved2_,_reserved3_,".ToLower()
+		If classHasFunction(classDecl, "SendMessage") Then
+			Emit "void _" + classid + "_SendMessage(BBOBJECT o, BBOBJECT message, BBOBJECT source);"
+		End If
 
-			classDecl.SemantParts()
+		Local reserved:String = ",New,Delete,ToString,Compare,SendMessage,_reserved1_,_reserved2_,_reserved3_,".ToLower()
 
-			'Local fdecls:TFuncDecl[] = classDecl.GetAllFuncDecls(Null, False)
-			For Local decl:TDecl=EachIn classDecl.Decls()
-			'For Local fdecl:TFuncDecl = EachIn fdecls
+		classDecl.SemantParts()
 
-				Local fdecl:TFuncDecl =TFuncDecl( decl )
-				If fdecl
+		'Local fdecls:TFuncDecl[] = classDecl.GetAllFuncDecls(Null, False)
+		For Local decl:TDecl=EachIn classDecl.Decls()
+		'For Local fdecl:TFuncDecl = EachIn fdecls
 
-					If reserved.Find("," + fdecl.IdentLower() + ",") = -1 Then
-						EmitClassFuncProto( fdecl )
-						Continue
-					End If
-				EndIf
+			Local fdecl:TFuncDecl =TFuncDecl( decl )
+			If fdecl
 
-				Local gdecl:TGlobalDecl =TGlobalDecl( decl )
-				If gdecl
-					MungDecl gdecl
-				'	Emit "static "+TransRefType( gdecl.ty )+" "+gdecl.munged+";"
+				If reserved.Find("," + fdecl.IdentLower() + ",") = -1 Then
+					EmitClassFuncProto( fdecl )
 					Continue
-				EndIf
-			Next
+				End If
+			EndIf
+
+			Local gdecl:TGlobalDecl =TGlobalDecl( decl )
+			If gdecl
+				MungDecl gdecl
+			'	Emit "static "+TransRefType( gdecl.ty )+" "+gdecl.munged+";"
+				Continue
+			EndIf
+		Next
 
-			Emit ""
+		Emit ""
 
-			' emit the class structure
-			Emit "struct BBClass_" + classid + " {"
-			If classDecl.superClass.ident = "Object" Then
-				Emit "BBClass*  super;"
-			Else
-				Emit "struct BBClass_" + classDecl.superClass.munged + "*  super;"
-			End If
-			Emit "void      (*free)( BBObject *o );"
-			Emit "BBDebugScope* debug_scope;"
-			Emit "int       instance_size;"
-			Emit "void      (*ctor)( BBOBJECT o );"
-			Emit "void      (*dtor)( BBOBJECT o );"
-			Emit "BBSTRING  (*ToString)( BBOBJECT x );"
-			Emit "int       (*Compare)( BBOBJECT x,BBOBJECT y );"
-			Emit "BBOBJECT  (*SendMessage)( BBOBJECT m,BBOBJECT s );"
-			Emit "BBINTERFACETABLE itable;"
-			Emit "void*     extra;"
-			Emit "void*     reserved;"
+		' emit the class structure
+		Emit "struct BBClass_" + classid + " {"
+		If classDecl.superClass.ident = "Object" Then
+			Emit "BBClass*  super;"
+		Else
+			Emit "struct BBClass_" + classDecl.superClass.munged + "*  super;"
+		End If
+		Emit "void      (*free)( BBObject *o );"
+		Emit "BBDebugScope* debug_scope;"
+		Emit "int       instance_size;"
+		Emit "void      (*ctor)( BBOBJECT o );"
+		Emit "void      (*dtor)( BBOBJECT o );"
+		Emit "BBSTRING  (*ToString)( BBOBJECT x );"
+		Emit "int       (*Compare)( BBOBJECT x,BBOBJECT y );"
+		Emit "BBOBJECT  (*SendMessage)( BBOBJECT m,BBOBJECT s );"
+		Emit "BBINTERFACETABLE itable;"
+		Emit "void*     extra;"
+		Emit "void*     reserved;"
+
+		EmitBBClassClassFuncProto(classDecl)
 
-			EmitBBClassClassFuncProto(classDecl)
+		Emit "};~n"
 
+		If classDecl.IsInterface() Then
+			Emit "struct " + classid + "_methods {"
+			EmitBBClassClassFuncProto(classDecl)
 			Emit "};~n"
+		End If
+
+		Emit "struct " + classid + "_obj {"
+		Emit "struct BBClass_" + classid + "* clas;"
+
+		BeginLocalScope
+		EmitClassFieldsProto(classDecl)
+		EndLocalScope
+
+		Emit "};"
+
+		Emit "extern struct BBClass_" + classid + " " + classid + ";"
+
+		EmitClassGlobalsProto(classDecl);
+
+		' fields
+		For Local decl:TFieldDecl = EachIn classDecl.Decls()
+			MungDecl decl
+		Next
+
+	End Method
 
-			If classDecl.IsInterface() Then
-				Emit "struct " + classid + "_methods {"
-				EmitBBClassClassFuncProto(classDecl)
-				Emit "};~n"
-			End If
 
+	Method EmitExternClassFuncProto( classDecl:TClassDecl )
+
+		If classDecl.superClass Then
+			EmitExternClassFuncProto(classDecl.superClass)
 		End If
 
+		For Local decl:TFuncDecl = EachIn classDecl.Decls()
+			decl.Semant()
 
-		'Emit "typedef struct " + classid + "_obj {"
-		If classDecl.IsExtern() Then
-			Emit "struct " + classid + "_ext {"
+			' code is written as a method, but emitted as a function pointer
+			' with self as the first parameter
+			Local func:TFuncDecl = TFuncDecl(decl.Copy())
+			Local argDecl:TArgDecl = New TArgDecl.Create("This", classDecl.objectType, Null)
 
-			BeginLocalScope
-			EmitClassFieldsProto(classDecl)
-			EndLocalScope
+			func.argDecls = [argDecl] + func.argDecls
+			
+			func.Semant()
+			
+			Local ty:TFunctionPtrType = New TFunctionPtrType
+			ty.func = func
+			
+			Emit TransType(ty, decl.Ident) + ";"
 
-			Emit "};"
-		Else
-			Emit "struct " + classid + "_obj {"
-			Emit "struct BBClass_" + classid + "* clas;"
+		Next
+	End Method
+
+	Method EmitExternClassTypeFuncProto( classDecl:TClassDecl )
+
+		Local doneCtorDtor:Int
+		Local iDecl:TClassDecl
+
+		For Local decl:TFuncDecl = EachIn classDecl.GetAllOriginalFuncDecls(Null, True)
+			decl.Semant()
+			
+			' first interface preceeds ctor/dtor
+			If Not doneCtorDtor
+				If Not iDecl And TClassDecl(decl.scope).IsInterface() Then
+					iDecl = TClassDecl(decl.scope)
+				End If
+				
+				If iDecl
+					If iDecl <> TClassDecl(decl.scope) Then
+						' a different interface
+						doneCtorDtor = True
+						Emit "void(*_ctor)();"
+						Emit "void(*_dtor)();"
+					End If
+				Else
+					doneCtorDtor = True
+					Emit "void(*_ctor)();"
+					Emit "void(*_dtor)();"
+				End If
+				
+			End If
+
+			' code is written as a method, but emitted as a function pointer
+			' with self as the first parameter
+			Local func:TFuncDecl = TFuncDecl(decl.Copy())
+			Local argDecl:TArgDecl = New TArgDecl.Create("This", classDecl.objectType, Null)
+
+			func.argDecls = [argDecl] + func.argDecls
+			
+			func.Semant()
+			
+			Local ty:TFunctionPtrType = New TFunctionPtrType
+			ty.func = func
+			
+			Emit TransType(ty, decl.Ident) + ";"
+
+		Next
+	End Method
+
+	Method EmitExternClassProto( classDecl:TClassDecl )
+
+		If classDecl.IsStruct() Then
+
+			Emit "struct " + classDecl.ident + " {"
 
 			BeginLocalScope
 			EmitClassFieldsProto(classDecl)
 			EndLocalScope
 
 			Emit "};"
-		End If
-
 
+		Else
+			Emit "typedef struct " + classDecl.ident + " " + classDecl.ident + ";"
+			
+			' vtable
+			Emit "struct " + classDecl.ident  + "Vtbl {"
+			
+			' methods
+			If classDecl.IsInterface() Then
+				EmitExternClassFuncProto(classDecl)
+			Else
+				EmitExternClassTypeFuncProto(classDecl)
+			End If
 
-		If Not classDecl.IsExtern() Then
-			Emit "extern struct BBClass_" + classid + " " + classid + ";"
+			Emit "};"
+			
+			Emit "struct " + classDecl.ident + " {"
+			Emit "struct " + classDecl.ident + "Vtbl* vtbl;"
+			Emit "};"
 
-			EmitClassGlobalsProto(classDecl);
 		End If
 
-		' fields
-		For Local decl:TFieldDecl = EachIn classDecl.Decls()
-			MungDecl decl
-		Next
-
 	End Method
-
+	
 	Method classHasFunction:Int(classDecl:TClassDecl, func:String)
 		Local f:String = func.ToLower()
 		For Local decl:TFuncDecl = EachIn classDecl.Decls()
@@ -3320,6 +3518,13 @@ End Rem
 			fld :+ TransFieldRef(decl, "o")
 
 			If decl.init Then
+				If TObjectType(decl.ty) And TObjectType(decl.ty).classdecl.IsExtern() And TObjectType(decl.ty).classdecl.IsStruct() Then
+					' skip for uninitialised extern type
+					If Not isPointerType(decl.ty) And TConstExpr(decl.init) And Not TConstExpr(decl.init).value Then
+						Continue
+					End If
+				End If
+
 				' initial value
 				fld :+ "= " + decl.init.Trans() + ";";
 			Else
@@ -3397,13 +3602,24 @@ End Rem
 	Method TransFieldRef:String(decl:TFieldDecl, variable:String, exprType:TType = Null)
 		Local s:String = variable
 
+		Local ind:String = "->"
+		If decl.scope And TClassDecl(decl.scope) And decl.scope.IsExtern() And TClassDecl(decl.scope).IsStruct() Then
+			If exprType And Not IsPointerType(exprType) Then
+				ind = "."
+			End If
+		End If
+
 		If variable.StartsWith("*") Then
 			variable = Bra(variable)
 		End If
 		
 		' Null test
-		If opt_debug Then
-			EmitDebugNullObjectError(variable)
+		If opt_debug
+			If TClassDecl(decl.scope) And decl.scope.IsExtern() And TClassDecl(decl.scope).IsStruct() Then
+				'
+			Else
+				EmitDebugNullObjectError(variable)
+			End If
 		End If
 
 		' array.length
@@ -3443,17 +3659,17 @@ End Rem
 		'End If
 
 		If IsNumericType(decl.ty) Then
-			s = variable + "->" + decl.munged + " "
+			s = variable + ind + decl.munged + " "
 		Else If TStringType(decl.ty) Then
-			s = variable + "->" + decl.munged + " "
+			s = variable + ind + decl.munged + " "
 		Else If TObjectType(decl.ty) Then
-			s = variable + "->" + decl.munged + " "
+			s = variable + ind + decl.munged + " "
 		Else If IsPointerType(decl.ty, 0, TType.T_POINTER) Then
-			s = variable + "->" + decl.munged + " "
+			s = variable + ind + decl.munged + " "
 		Else If TFunctionPtrType(decl.ty) Then
-			s = variable + "->" + decl.munged + " "
+			s = variable + ind + decl.munged + " "
 		Else If TArrayType(decl.ty) Then
-			s = variable + "->" + decl.munged + " "
+			s = variable + ind + decl.munged + " "
 		End If
 
 		Return s
@@ -3737,8 +3953,16 @@ End Rem
 				EndIf
 
 			Next
+			
+			Local flags:String = "E"
+			
+			If classDecl.IsInterface() Then
+				flags :+ "I"
+			Else If classDecl.IsStruct() Then
+				flags :+ "S"
+			End If
 
-			Emit "}E=0", False
+			Emit "}" + flags + "=0", False
 		End If
 
 		'PopMungScope
@@ -3960,7 +4184,11 @@ End If
 
 			Local cdecl:TClassDecl=TClassDecl( decl )
 			If cdecl
-				EmitClassProto cdecl
+				If Not cdecl.IsExtern()
+					EmitClassProto cdecl
+				Else
+					EmitExternClassProto cdecl
+				End If
 				Continue
 			EndIf
 		Next

+ 85 - 16
decl.bmx

@@ -22,26 +22,27 @@
 '    distribution.
 '
 
-Const DECL_EXTERN:Int=		$010000
-Const DECL_PRIVATE:Int=	    $020000
-Const DECL_ABSTRACT:Int=	$040000
-Const DECL_FINAL:Int=		$080000
+Const DECL_EXTERN:Int=      $010000
+Const DECL_PRIVATE:Int=     $020000
+Const DECL_ABSTRACT:Int=    $040000
+Const DECL_FINAL:Int=       $080000
 
 Const DECL_SEMANTED:Int=    $100000
 Const DECL_SEMANTING:Int=   $200000
 
 Const DECL_POINTER:Int=     $400000
 
-Const DECL_ARG:Int=        $800000
-Const DECL_INITONLY:Int=  $1000000
+Const DECL_ARG:Int=         $800000
+Const DECL_INITONLY:Int=   $1000000
 
-Const DECL_NODEBUG:Int=   $2000000
+Const DECL_NODEBUG:Int=    $2000000
 
-Const DECL_API_WIN32:Int=$10000000
+Const DECL_API_WIN32:Int= $10000000
 Const DECL_API_OS:Int=DECL_API_WIN32
 
-Const CLASS_INTERFACE:Int=	$001000
-Const CLASS_THROWABLE:Int=	$002000
+Const CLASS_INTERFACE:Int=  $001000
+Const CLASS_THROWABLE:Int=  $002000
+Const CLASS_STRUCT:Int=     $004000
 
 Global _env:TScopeDecl
 Global _envStack:TList=New TList
@@ -673,7 +674,7 @@ Type TScopeDecl Extends TDecl
 'DebugLog "Adding " + decl.ident
 			declsMap.Insert decl.IdentLower(),decl
 		Else
-			Err "Duplicate identifier '"+ident+"'."
+			Err "Duplicate identifier '"+decl.ident+"'."
 		EndIf
 
 	End Method
@@ -1522,6 +1523,10 @@ End Rem
 	Method IsFinalized:Int()
 		Return (attrs & CLASS_FINALIZED)<>0
 	End Method
+	
+	Method IsStruct:Int()
+		Return (attrs & CLASS_STRUCT)<>0
+	End Method
 
 	Method ExtendsObject:Int()
 		Return (attrs & CLASS_EXTENDSOBJECT)<>0
@@ -1649,6 +1654,61 @@ End Rem
 		
 		Return funcs
 	End Method
+
+	' returns a list of original function decls (i.e. decls in the scope of their original declarations).
+	' this is useful for generating vtables for extern types
+	Method GetAllOriginalFuncDecls:TFuncDecl[](funcs:TFuncDecl[] = Null, includeSuper:Int = True)
+		If Not funcs Then
+			funcs = New TFuncDecl[0]
+		End If
+		
+		If superClass And includeSuper Then
+			funcs = superClass.GetAllOriginalFuncDecls(funcs, True)
+		End If
+
+		' interface methods
+		For Local iface:TClassDecl=EachIn implmentsAll
+			For Local func:TFuncDecl=EachIn iface._decls
+				Local matched:Int = False
+
+'				For Local i:Int = 0 Until funcs.length
+'					' found a match - we are overriding it
+'					If func.IdentLower() = funcs[i].IdentLower() Then
+'						matched = True
+'						Exit
+'					End If
+'				Next
+				
+				If Not matched Then
+					funcs :+ [func]
+				End If
+			Next
+		Next
+
+		
+		For Local func:TFuncDecl = EachIn _decls
+		
+			Local matched:Int = False
+			
+			' dont count any that are already in the funcs list
+			For Local i:Int = 0 Until funcs.length
+				' found a match - we are overriding it
+				If func.IdentLower() = funcs[i].IdentLower() Then
+					matched = True
+					' set this to our own func
+					'funcs[i] = func
+					Exit
+				End If
+			Next
+			
+			If Not matched Then
+				funcs :+ [func]
+			End If
+		
+		Next
+		
+		Return funcs
+	End Method
 	
 	Method ExtendsClass:Int( cdecl:TClassDecl )
 		'If Self=nullObjectClass Return True
@@ -1686,7 +1746,10 @@ End Rem
 		If superTy
 			'superClass=superTy.FindClass()
 			superClass=superTy.SemantClass()
-			If superClass.IsInterface() Err superClass.ToString()+" is an interface, not a class."
+			If superClass.IsInterface() Then
+				If Not IsExtern() Or Not superClass.IsExtern() Err superClass.ToString()+" is an interface, not a class."
+				If (IsExtern() And Not superClass.IsExtern()) Or (superClass.IsExtern() And Not IsExtern()) Err "Extern and non extern types cannot be mixed."
+			End If
 			If superClass.IsFinal() Err "Final types cannot be extended."
 		EndIf
 		
@@ -1709,9 +1772,10 @@ End Rem
 				implsall.Push tdecl_
 			Next
 		Next
-		implmentsAll=New TClassDecl[implsall.Length()]
-		For Local i:Int=0 Until implsall.Length()
-			implmentsAll[i]=TClassDecl(implsall.Get(i))
+		Local length:Int = implsall.Length()
+		implmentsAll=New TClassDecl[length]
+		For Local i:Int=0 Until length
+			implmentsAll[i]=TClassDecl(implsall.Get(length - i - 1))
 		Next
 		implments=impls
 
@@ -1924,6 +1988,11 @@ End Rem
 				Local ints:TMap = GetInterfaces()
 
 				For Local iface:TClassDecl=EachIn ints.Values()
+				
+					If (Not IsExtern() And iface.IsExtern()) Or (IsExtern() And Not iface.IsExtern()) Then
+						Err "Cannot mix Extern and non Extern Types and Interfaces."
+					End If
+				
 					For Local decl:TFuncDecl=EachIn iface.SemantedMethods()
 						Local found:Int
 
@@ -1932,7 +2001,7 @@ End Rem
 						While cdecl And Not found
 							For Local decl2:TFuncDecl=EachIn cdecl.SemantedMethods( decl.ident )
 								If decl.EqualsFunc( decl2 )
-									If decl2.munged
+									If decl2.munged And Not iface.IsExtern()
 										Err "Extern methods cannot be used to implement interface methods."
 									EndIf
 									found=True

+ 34 - 11
expr.bmx

@@ -217,11 +217,13 @@ Type TExpr
 			If TFunctionPtrType( lhs ) Return lhs
 			If TFunctionPtrType( rhs ) Return rhs
 		End If
+		If TULongType( lhs ) Or TULongType( rhs ) Return New TULongType
 		If TSizeTType( lhs ) Or TSizeTType( rhs ) Return New TSizeTType
+		If TLongType( lhs ) And TUIntType( rhs ) Return New TULongType
+		If TUIntType( lhs ) And TLongType( rhs ) Return New TULongType
 		If TLongType( lhs ) Or TLongType( rhs ) Return New TLongType
-		If TULongType( lhs ) Or TULongType( rhs ) Return New TULongType
-		If TIntType( lhs ) Or TIntType( rhs ) Return New TIntType
 		If TUIntType( lhs ) Or TUIntType( rhs ) Return New TUIntType
+		If TIntType( lhs ) Or TIntType( rhs ) Return New TIntType
 		If TObjectType( lhs ) And TNullDecl(TObjectType( lhs ).classDecl) Then
 			Return rhs
 		End If
@@ -345,9 +347,12 @@ End Type
 Type TConstExpr Extends TExpr
 	Field ty:TType
 	Field value$
+	Field originalValue$
 
 	Method Create:TConstExpr( ty:TType,value$ )
-
+	
+		originalValue = value
+		
 		If TNumericType( ty ) And IsPointerType(ty, 0, TType.T_POINTER) Then
 			Self.ty=ty
 			If value Then
@@ -358,7 +363,7 @@ Type TConstExpr Extends TExpr
 			Return Self
 		End If
 		
-		If TIntType( ty ) Or TShortType( ty ) Or TByteType( ty ) Or TLongType( ty )
+		If TIntType( ty ) Or TShortType( ty ) Or TByteType( ty ) Or TLongType( ty ) Or TUIntType( ty ) Or TULongType( ty )
 			Local radix:Int
 			If value.StartsWith( "%" )
 				radix=1
@@ -407,6 +412,10 @@ Type TConstExpr Extends TExpr
 		Self.value=value
 		Return Self
 	End Method
+	
+	Method UpdateType(ty:TType)
+		Create(ty, originalValue)
+	End Method
 
 	Method Copy:TExpr()
 		Return New TConstExpr.Create( ty,value )
@@ -705,7 +714,8 @@ Type TNewObjectExpr Extends TExpr
 		If classDecl.args And Not classDecl.instanceof Err "Cannot create instance of a generic class."
 
 		If classDecl.IsExtern()
-			If args Err "No suitable constructor found for class "+classDecl.ToString()+"."
+			Err "Cannot create instance of an extern type"
+			'If args Err "No suitable constructor found for class "+classDecl.ToString()+"."
 '		Else
 'DebugStop
 '			ctor=classDecl.FindFuncDecl( "new",args )
@@ -897,8 +907,12 @@ Type TSelfExpr Extends TExpr
 	Method Semant:TExpr()
 		If exprType Return Self
 
-		If _env.FuncScope().IsStatic() Err "Illegal use of Self within static scope."
-		exprType=New TObjectType.Create( _env.ClassScope() )
+		'If _env.FuncScope().IsStatic() Err "Illegal use of Self within static scope."
+		Local scope:TClassDecl = _env.ClassScope()
+		If Not scope Then
+			Err "'Self' can only be used within methods."
+		End If
+		exprType=New TObjectType.Create( scope )
 		Return Self
 	End Method
 
@@ -1088,11 +1102,11 @@ Type TCastExpr Extends TExpr
 '			Return expr
 '		End If
 
-		If TIntType(ty) And TObjectType(src) Then
+'		If TIntType(ty) And TObjectType(src) Then
 ' DebugStop ' Bah woz ere
-			exprType = ty
-			Return expr
-		End If
+'			exprType = ty
+'			Return expr
+'		End If
 
 		If TObjectType(src) And TNullDecl(TObjectType(src).classDecl) Then
 			exprType = ty
@@ -1640,6 +1654,15 @@ Type TIndexExpr Extends TExpr
 		If exprType Return Self
 
 		expr=expr.Semant()
+
+		' for functions and index access, use a new local variable
+		If Not TVarExpr(expr) And Not TMemberVarExpr(expr) Then
+			Local tmp:TLocalDecl=New TLocalDecl.Create( "", expr.exprType, expr,, True )
+			tmp.Semant()
+			Local v:TVarExpr = New TVarExpr.Create( tmp )
+			expr = New TStmtExpr.Create( New TDeclStmt.Create( tmp ), v ).Semant()
+		End If
+
 		For Local i:Int = 0 Until index.length
 			index[i]=index[i].SemantAndCast( New TUIntType, True )
 		Next

+ 70 - 6
iparser.bmx

@@ -264,8 +264,18 @@ Type TIParser
 							class.attrs :| DECL_ABSTRACT | DECL_FINAL
 						Else If CParse("E")
 							class.attrs :| DECL_EXTERN
+
+							ApplyFunctionAttributes(class, DECL_EXTERN)
 						Else If CParse("AI")
 							class.attrs :| CLASS_INTERFACE | DECL_ABSTRACT
+
+							ApplyFunctionAttributes(class, DECL_ABSTRACT)
+						Else If CParse("EI")
+							class.attrs :| DECL_EXTERN | CLASS_INTERFACE
+							
+							ApplyFunctionAttributes(class, DECL_EXTERN | DECL_ABSTRACT)
+						Else If CParse("ES")
+							class.attrs :| DECL_EXTERN | CLASS_STRUCT
 						End If
 'DebugStop
 						If CParse( "=" )
@@ -808,14 +818,20 @@ Type TIParser
 		Repeat		
 			If CParse( "F" )
 				attrs:|DECL_FINAL
+			Else If CParse( "FW" )
+				attrs:|DECL_FINAL | DECL_API_WIN32
 			Else If CParse( "A" )
 				attrs:|DECL_ABSTRACT
-			Else If CParse( "property" )
-				If attrs & FUNC_METHOD
-					attrs:|FUNC_PROPERTY
-				Else
-					Err "Only methods can be properties."
-				EndIf
+			Else If CParse( "AW" )
+				attrs:|DECL_ABSTRACT | DECL_API_WIN32
+			Else If CParse( "W" )
+				attrs:|DECL_API_WIN32
+			'Else If CParse( "property" )
+			'	If attrs & FUNC_METHOD
+			'		attrs:|FUNC_PROPERTY
+			'	Else
+			'		Err "Only methods can be properties."
+			'	EndIf
 			Else
 				Exit
 			EndIf
@@ -1239,6 +1255,48 @@ End Rem
 				End If
 			End If
 			
+			CParse("&")
+		Case "?"
+			NextToke
+			
+			attrs :| DECL_EXTERN
+			
+			If CParse("?") Then
+				attrs :| CLASS_INTERFACE
+			End If
+			
+			ty=ParseNewType()
+			
+			If CParse("*") Then
+				If TIdentType(ty) Then
+					ty = TType.MapToPointerType(ty)
+
+					While CParse( "*" )
+						ty = TType.MapToPointerType(ty)
+					Wend
+
+				End If
+			End If
+			
+			CParse("&")
+		Case "~~"
+			NextToke
+			
+			attrs :| DECL_EXTERN | CLASS_STRUCT
+			
+			ty=ParseNewType()
+			
+			If CParse("*") Then
+				If TIdentType(ty) Then
+					ty = TType.MapToPointerType(ty)
+
+					While CParse( "*" )
+						ty = TType.MapToPointerType(ty)
+					Wend
+
+				End If
+			End If
+			
 			CParse("&")
 		Case "@"
 			NextToke
@@ -1380,6 +1438,12 @@ End Rem
 		End If
 		Return ParseIdentType()
 	End Method
+	
+	Method ApplyFunctionAttributes(classDecl:TClassDecl, attrs:Int)
+		For Local decl:TFuncDecl = EachIn classDecl._decls
+			decl.attrs :| attrs
+		Next
+	End Method
 
 	Method SetErr()
 		If _toker.Path()

+ 100 - 72
parser.bmx

@@ -75,8 +75,10 @@ Type TForEachinStmt Extends TLoopStmt
 			If varlocal
 
 				' array of object ?
-				
-				If TArrayType( expr.exprType ) And TObjectType(TArrayType( expr.exprType ).elemType) Then
+
+				If TArrayType( expr.exprType ) And TObjectType(TArrayType( expr.exprType ).elemType) And (Not TObjectType(TArrayType( expr.exprType ).elemType).classdecl.IsExtern() ..
+							Or (TObjectType(TArrayType( expr.exprType ).elemType).classdecl.IsExtern() ..
+							And IsPointerType(TArrayType( expr.exprType ).elemType))) Then
 
 					Local cExpr:TExpr
 					
@@ -443,7 +445,7 @@ Type TParser
 	Method ParseIdent$()
 		Select _toke
 		Case "@" NextToke
-		Case "string","object"
+		Case "string","object", "self"
 		Default
 			If _tokeType<>TOKE_IDENT Err "Syntax error - expecting identifier."
 		End Select
@@ -1204,7 +1206,7 @@ Type TParser
 
 				Local ty:TType = ParseConstNumberType()
 				If ty Then
-					TConstExpr(expr).ty = ty
+					TConstExpr(expr).UpdateType(ty)
 				End If
 			Case TOKE_LONGLIT
 				expr=New TConstExpr.Create( New TLongType,_toke )
@@ -2046,10 +2048,14 @@ End Rem
 					NextToke
 				Case "const","global"
 					mdecl.InsertDecls ParseDecls( _toke,attrs )
+				Case "struct"
+					mdecl.InsertDecl ParseClassDecl( _toke,attrs | CLASS_STRUCT )
 				Case "type"
 					mdecl.InsertDecl ParseClassDecl( _toke,attrs )
 				Case "function"
 					mdecl.InsertDecl ParseFuncDecl( _toke,attrs )
+				Case "interface"
+					mdecl.InsertDecl ParseClassDecl( _toke,attrs | CLASS_INTERFACE )
 				Default
 					If _toke <> "end" And _toke <> "endextern" Then
 						Err "Expecting expression but encountered '"+_toke+"'"
@@ -2103,18 +2109,27 @@ End Rem
 			Case "#"
 				Local decl:TLoopLabelDecl = ParseLoopLabelDecl()
 				NextToke
-				Select _toke.ToLower()
-					Case "while"
-						ParseWhileStmt(decl)
-					Case "repeat"
-						ParseRepeatStmt(decl)
-					Case "for"
-						ParseForStmt(decl)
-					Case "defdata"
-						ParseDefDataStmt(decl)
-					Default
-						Err "Labels must appear before a loop or DefData statement"
-				End Select
+				While _toke
+					SetErr
+					Select _toke.ToLower()
+						Case "~n"
+							NextToke
+						Case "while"
+							ParseWhileStmt(decl)
+							Exit
+						Case "repeat"
+							ParseRepeatStmt(decl)
+							Exit
+						Case "for"
+							ParseForStmt(decl)
+							Exit
+						Case "defdata"
+							ParseDefDataStmt(decl)
+							Exit
+						Default
+							Err "Labels must appear before a loop or DefData statement"
+					End Select
+				Wend
 			Case "release"
 				ParseReleaseStmt()
 			Case "defdata"
@@ -2665,9 +2680,9 @@ End Rem
 		Local imps:TIdentType[]
 		Local meta:String
 
-		If (attrs & CLASS_INTERFACE) And (attrs & DECL_EXTERN)
-			Err "Interfaces cannot be extern."
-		EndIf
+		'If (attrs & CLASS_INTERFACE) And (attrs & DECL_EXTERN)
+		'	Err "Interfaces cannot be extern."
+		'EndIf
 Rem
 		If CParse( "<" )
 
@@ -2700,19 +2715,20 @@ End Rem
 			'	Err "Extends cannot be used with class parameters."
 			'EndIf
 
-			If CParse( "null" )
-
-				If attrs & CLASS_INTERFACE
-					Err "Interfaces cannot extend null"
-				EndIf
-
-				If Not (attrs & DECL_EXTERN)
-					Err "Only extern objects can extend null."
+'			If CParse( "null" )
+'
+				If attrs & CLASS_STRUCT
+					Err "Structs cannot be extended"
 				EndIf
-
-				superTy=Null
-
-			Else If attrs & CLASS_INTERFACE
+'
+'				If Not (attrs & DECL_EXTERN)
+'					Err "Only extern objects can extend null."
+'				EndIf
+'
+'				superTy=Null
+'
+'			Else
+			If attrs & CLASS_INTERFACE And Not (attrs & DECL_EXTERN)
 
 				Local nimps:Int
 				Repeat
@@ -2733,9 +2749,9 @@ End Rem
 
 		If CParse( "implements" )
 
-			If attrs & DECL_EXTERN
-				Err "Implements cannot be used with external classes."
-			EndIf
+			'If attrs & DECL_EXTERN
+			'	Err "Implements cannot be used with external classes."
+			'EndIf
 
 			If attrs & CLASS_INTERFACE
 				Err "Implements cannot be used with interfaces."
@@ -2761,6 +2777,10 @@ End Rem
 					Err "Final cannot be used with interfaces."
 				End If
 				
+				If attrs & CLASS_STRUCT
+					Err "Final cannot be used with structs."
+				End If
+				
 				If attrs & DECL_FINAL
 					Err "Duplicate type attribute."
 				End If
@@ -2777,6 +2797,10 @@ End Rem
 					Err "Abstract cannot be used with interfaces."
 				EndIf
 				
+				If attrs & CLASS_STRUCT
+					Err "Abstract cannot be used with structs."
+				EndIf
+				
 				If attrs & DECL_ABSTRACT
 					Err "Duplicate type attribute."
 				End If
@@ -2793,6 +2817,10 @@ End Rem
 
 		'check for metadata
 		If CParse( "{" )
+			If attrs & CLASS_STRUCT
+				Err "Structs cannot store metadata."
+			EndIf
+
 			meta = ParseMetaData()
 		End If
 
@@ -2810,7 +2838,7 @@ End Rem
 
 		'If classDecl.IsTemplateArg() Return classDecl
 
-		Local decl_attrs:Int=(attrs & DECL_EXTERN) | (attrs & DECL_NODEBUG)
+		Local decl_attrs:Int=(attrs & DECL_EXTERN) | (attrs & DECL_NODEBUG) | (attrs & DECL_API_WIN32)
 
 		Local method_attrs:Int=decl_attrs|FUNC_METHOD | (attrs & DECL_NODEBUG)
 		If attrs & CLASS_INTERFACE method_attrs:|DECL_ABSTRACT
@@ -2825,13 +2853,29 @@ End Rem
 				If attrs & CLASS_INTERFACE Then
 					Err "Syntax error - expecting End Interface, not 'EndType'"
 				End If
+				If attrs & CLASS_STRUCT Then
+					Err "Syntax error - expecting End Struct, not 'EndType'"
+				End If
+				toke = Null
+				NextToke
+				Exit
+			Case "endstruct"
+				If attrs & CLASS_INTERFACE Then
+					Err "Syntax error - expecting End Interface, not 'EndStruct'"
+				End If
+				If Not (attrs & CLASS_STRUCT) Then
+					Err "Syntax error - expecting End Type, not 'EndStruct'"
+				End If
 				toke = Null
 				NextToke
 				Exit
 			Case "endinterface"
-				If Not (attrs & CLASS_INTERFACE) Then
+				If Not (attrs & CLASS_INTERFACE) And Not (attrs & CLASS_STRUCT) Then
 					Err "Syntax error - expecting End Type, not 'EndInterface'"
 				End If
+				If Not (attrs & CLASS_INTERFACE) And (attrs & CLASS_STRUCT) Then
+					Err "Syntax error - expecting End Struct, not 'EndInterface'"
+				End If
 				toke = Null
 				NextToke
 				Exit
@@ -2842,11 +2886,25 @@ End Rem
 				NextToke
 				decl_attrs=decl_attrs & ~DECL_PRIVATE
 			Case "const","global","field"
+				If attrs & DECL_EXTERN Then
+					If (attrs & CLASS_INTERFACE) Then
+						Err "Extern Interfaces can only contain methods."
+					End If
+					If Not (attrs & CLASS_STRUCT) Then
+						Err "Extern Types can only contain methods."
+					End If
+				End If
 				If (attrs & CLASS_INTERFACE) And _toke<>"const"
 					Err "Interfaces can only contain constants and methods."
 				EndIf
+				If (attrs & CLASS_STRUCT) And _toke<>"field"
+					Err "Structs can only contain fields."
+				EndIf
 				classDecl.InsertDecls ParseDecls( _toke,decl_attrs )
 			Case "method"
+				If attrs & CLASS_STRUCT Then
+					Err "Structs can only contain fields."
+				EndIf
 				Local decl:TFuncDecl=ParseFuncDecl( _toke,method_attrs )
 				If decl.IsCtor() decl.retTypeExpr=New TObjectType.Create( classDecl )
 				classDecl.InsertDecl decl
@@ -2854,6 +2912,12 @@ End Rem
 				If (attrs & CLASS_INTERFACE)
 					Err "Interfaces can only contain constants and methods."
 				EndIf
+				If attrs & CLASS_STRUCT Then
+					Err "Structs can only contain fields."
+				EndIf
+				If attrs & DECL_EXTERN Then
+					Err "Extern Types can only contain methods."
+				End If
 				Local decl:TFuncDecl=ParseFuncDecl( _toke,decl_attrs )
 				classDecl.InsertDecl decl
 			Default
@@ -3182,43 +3246,7 @@ End Rem
 			Case "extern"
 
 				ParseExternBlock(_module, attrs)
-Rem
-				NextToke
 
-				If _tokeType=TOKE_STRINGLIT
-					DebugLog "EXTERN : " + ParseStringLit()
-				End If
-
-
-				attrs=DECL_EXTERN
-				If CParse( "private" ) attrs=attrs|DECL_PRIVATE
-
-
-				While _toke<>"endextern"
-					If CParse( "end" )
-						If Parse("extern")
-							Exit
-						End If
-					EndIf
-
-					SetErr
-					Select _toke
-						Case "~n"
-							NextToke
-						Case "const","global"
-							_module.InsertDecls ParseDecls( _toke,attrs )
-						Case "type"
-							_module.InsertDecl ParseClassDecl( _toke,attrs )
-						Case "function"
-							_module.InsertDecl ParseFuncDecl( _toke,attrs )
-						Case "rem"
-							ParseRemStmt()
-					End Select
-
-				Wend
-
-				attrs = 0
-End Rem
 			Case "const"
 				_module.InsertDecls ParseDecls( _toke,attrs )
 			Case "global"

+ 9 - 1
stmt.bmx

@@ -505,8 +505,16 @@ Type TForStmt Extends TLoopStmt
 			TCastExpr(TBinaryCompareExpr(expr).rhs).ty = TVarExpr(TAssignStmt(init).lhs).exprType.Copy()
 			TCastExpr(TBinaryMathExpr(TAssignStmt(incr).rhs).rhs).ty = TVarExpr(TAssignStmt(init).lhs).exprType.Copy()
 		End If
-		
+
 		expr=expr.Semant()
+
+		' for anything other than a const value, use a new local variable
+		If Not TConstExpr(TBinaryCompareExpr(expr).rhs) Then
+			Local tmp:TLocalDecl=New TLocalDecl.Create( "", TBinaryCompareExpr(expr).rhs.exprType,TBinaryCompareExpr(expr).rhs,, True )
+			tmp.Semant()
+			Local v:TVarExpr = New TVarExpr.Create( tmp )
+			TBinaryCompareExpr(expr).rhs = New TStmtExpr.Create( New TDeclStmt.Create( tmp ), v ).Semant()
+		End If
 		
 		_loopnest:+1
 		block.Semant

+ 1 - 1
toker.bmx

@@ -55,7 +55,7 @@ Type TToker
 	"alias;rem;endrem;throw;assert;try;catch;nodebug;incbin;"+ ..
 	"endselect;endmethod;endfunction;endtype;endextern;endtry;endwhile;pi;release;defdata;readdata;restoredata;" + ..
 	"interface;endinterface;implements;"+ ..
-	"size_t;uint;ulong;"
+	"size_t;uint;ulong;struct;endstruct;"
 
 	Global _symbols$[]=[ "..","[]",":*",":/",":+",":-",":|",":&",":~~",":shr",":shl",":sar",":mod" ]
 	Global _symbols_map$[]=[ "..","[]","*=","/=","+=","-=","|=","&=","^=",">>=", "<<=",">>=","%=" ]

+ 15 - 1
type.bmx

@@ -834,7 +834,21 @@ Type TIdentType Extends TType
 		
 		If i=-1
 			tyid=ident.ToLower()
-			ty=_env.FindType( tyid,targs )
+			
+			If tyid = "self" Then
+				' find owning class
+				Local scope:TClassDecl = _env.ClassScope()
+				If scope Then
+					tyid = scope.ident
+					ty = New TObjectType.Create(scope)
+				Else
+					Err "'Self' can only be used within methods."
+				End If
+			End If
+			
+			If Not ty Then
+				ty=_env.FindType( tyid,targs )
+			End If
 
 			' finally scan all modules for it
 			If Not ty Then