2
0
Эх сурвалжийг харах

Added Override method property. Fixes #390.

woollybah 6 жил өмнө
parent
commit
cabf3c898c
4 өөрчлөгдсөн 149 нэмэгдсэн , 80 устгасан
  1. 130 78
      decl.bmx
  2. 11 1
      options.bmx
  3. 7 0
      parser.bmx
  4. 1 1
      toker.bmx

+ 130 - 78
decl.bmx

@@ -27,6 +27,7 @@ Const DECL_PRIVATE:Int=       $020000
 Const DECL_ABSTRACT:Int=      $040000
 Const DECL_FINAL:Int=         $080000
 Const DECL_READ_ONLY:Int=     $000100
+Const DECL_OVERRIDE:Int=    $40000000
 
 Const DECL_SEMANTED:Int=      $100000
 Const DECL_SEMANTING:Int=     $200000
@@ -52,6 +53,7 @@ Const CLASS_INTERFACE:Int=    $002000
 Const CLASS_THROWABLE:Int=    $004000
 Const CLASS_STRUCT:Int=       $008000
 Const CLASS_GENERIC:Int=      $001000
+Const CLASS_FLAGS:Int = CLASS_INTERFACE | CLASS_THROWABLE | CLASS_STRUCT | CLASS_GENERIC
 
 Const SCOPE_FUNC:Int = 0
 Const SCOPE_CLASS_LOCAL:Int = 1
@@ -994,9 +996,9 @@ Type TScopeDecl Extends TDecl
 	End Method
 	
 
-	Method FindDecl:Object( ident$, override:Int = False )
+	Method FindDecl:Object( ident$, _override:Int = False )
 	
-		If Not override And _env<>Self Return GetDecl( ident )
+		If Not _override And _env<>Self Return GetDecl( ident )
 		
 		Local tscope:TScopeDecl=Self
 		While tscope
@@ -1049,13 +1051,13 @@ Type TScopeDecl Extends TDecl
 	End Method
 	
 	' returns a list of all matching named decls in scope
-	Method FindDeclList:Object(ident:String, override:Int = False, declList:TFuncDeclList = Null, maxSearchDepth:Int = SCOPE_ALL, skipMultipleClassScopes:Int = False )
+	Method FindDeclList:Object(ident:String, _override:Int = False, declList:TFuncDeclList = Null, maxSearchDepth:Int = SCOPE_ALL, skipMultipleClassScopes:Int = False )
 
 		If Not declList Then
 			declList = New TFuncDeclList
 		End If
 	
-		If Not override And _env<>Self Return GetDeclList( ident, declList, maxSearchDepth )
+		If Not _override And _env<>Self Return GetDeclList( ident, declList, maxSearchDepth )
 		
 		Local hadClassScope:Int
 		Local tscope:TScopeDecl=Self
@@ -2101,89 +2103,35 @@ Type TFuncDecl Extends TBlockDecl
 		'check we exactly match an override
 		If sclass 'And IsMethod()
 
+			Local found:Int
+
 			While sclass
 				Local errorDetails:String = ""
 
-				Local found:Int
-				For Local decl:TFuncDecl=EachIn sclass.FuncDecls( )
-					
-					If decl.IdentLower() = IdentLower() Then
-
-						If IdentLower() = "new" Continue
-						If IdentLower() = "delete" Continue
-
-						found=True
-
-						If Not decl.IsSemanted() Then
-							decl.Semant
-						End If
-
-						' check void return type strictness, and fail if appropriate.
-						Local voidReturnTypeFail:Int = False
-						' super has void return type... so it is superstrict (or inherited from)
-						If TVoidType(decl.retType) And TIntType(retType) Then
-							' if we are only strict, we may fail on type mismatch
-							If Not ModuleScope().IsSuperStrict() Then
-								' we have the option of upgrading our return type to match superstrict parent
-								If opt_strictupgrade And strictVoidToInt Then
-									retType = TType.voidType
-								Else
-									' otherwise...
-									voidReturnTypeFail = True
-								End If
-							End If
-						End If
-
-						If EqualsFunc( decl ) And Not voidReturnTypeFail
+				found = MatchesFunction(sclass, strictVoidToInt, errorDetails)
 
-							' check we aren't attempting to assign weaker access modifiers
-							If (IsProtected() And decl.IsPublic()) Or (IsPrivate() And (decl.IsProtected() Or decl.IsPublic())) Then
-							
-								Err PrivilegeError(Self, decl)
-							
-							End If
-						
-							If (TObjectType(retType) And TObjectType(decl.retType )) Or (TArrayType(retType) And TArrayType(decl.retType)) Then
-								If Not retType.EqualsType( decl.retType ) And retType.ExtendsType( decl.retType ) Then
-									returnTypeSubclassed = True
-								End If
-							End If
-							
-							overrides=TFuncDecl( decl.actual )
-						Else
-							' method overloading?
-							If Not EqualsArgs(decl) Then
-								found = False
-								Continue
-							End If
-							
-							'prepare a more detailed error message
-							If (Not retType.EqualsType( decl.retType ) Or Not retType.ExtendsType( decl.retType )) Or (decl.retType And Not decl.retType.EqualsType( retType )) Or voidReturnTypeFail
-								errorDetails :+ "Return type is ~q"+retType.ToString()+"~q, expected ~q"+decl.retType.ToString()+"~q. "
-								If voidReturnTypeFail Then
-									errorDetails :+ "You may have Strict type overriding SuperStrict type. "
-								End If
-							Else
-								found = False
-								Continue
-							End If
+				' check interfaces?
+				If Not found Then
+					If sclass = cdecl.superClass Then
+						found = MatchesInterfaceFunction(cdecl, strictVoidToInt, errorDetails)
+					End If
 
-							Local argCount:Int = Min(argDecls.Length, decl.argDecls.Length)
-							If argCount > 0
-								For Local i:Int=0 Until argCount
-									If Not argDecls[i].ty.EqualsType( decl.argDecls[i].ty )
-										errorDetails :+ "Argument #"+(i+1)+" is ~q" + argDecls[i].ty.ToString()+"~q, expected ~q"+decl.argDecls[i].ty.ToString()+"~q. "
-									End If
-								Next
-							EndIf
-							'remove last space
-							errorDetails = errorDetails.Trim()
-						EndIf
+					If Not found Then
+						found = MatchesInterfaceFunction(sclass, strictVoidToInt, errorDetails)
 					End If
-				Next
+				End If
+				
 				If found
 					If Not overrides Err "Overriding method does not match any overridden method. (Detail: " + errorDetails+")"
 					If overrides.IsFinal() Err "Final methods cannot be overridden."
+					If Not (attrs & DECL_OVERRIDE) And opt_require_override And Not declImported Then
+						Local msg:String = "Overriding method '" + ident + "' should specify 'Override' property."
+						If Not opt_override_error Then
+							Warn msg
+						Else
+							Err msg
+						End If
+					End If
 					' for overrides, make the ident match that of the superclass
 					ident = overrides.ident
 					
@@ -2191,6 +2139,10 @@ Type TFuncDecl Extends TBlockDecl
 				EndIf
 				sclass=sclass.superClass
 			Wend
+			
+			If Not found And attrs & DECL_OVERRIDE Then
+				Err "Method does not override method from its super type."
+			End If
 		EndIf
 
 		'append a return statement if necessary
@@ -2210,6 +2162,106 @@ Type TFuncDecl Extends TBlockDecl
 		
 		Super.OnSemant()
 	End Method
+	
+	Method MatchesInterfaceFunction:Int(cdecl:TClassDecl, strictVoidToInt:Int, errorDetails:String Var)
+		Local found:Int
+
+		If Not found Then
+			For Local idecl:TClassDecl = EachIn cdecl.implments
+				found = MatchesFunction(idecl, strictVoidToInt, errorDetails)
+			
+				If Not found Then
+					found = MatchesInterfaceFunction(idecl, strictVoidToInt, errorDetails)
+				End If
+				
+				If found Then
+					Exit
+				End If
+			Next
+		End If
+		Return found
+	End Method
+
+	Method MatchesFunction:Int(sclass:TClassDecl, strictVoidToInt:Int, errorDetails:String Var)
+		Local found:Int
+		For Local decl:TFuncDecl=EachIn sclass.FuncDecls( )
+			
+			If decl.IdentLower() = IdentLower() Then
+
+				If IdentLower() = "new" Continue
+				If IdentLower() = "delete" Continue
+
+				found=True
+
+				If Not decl.IsSemanted() Then
+					decl.Semant
+				End If
+
+				' check void return type strictness, and fail if appropriate.
+				Local voidReturnTypeFail:Int = False
+				' super has void return type... so it is superstrict (or inherited from)
+				If TVoidType(decl.retType) And TIntType(retType) Then
+					' if we are only strict, we may fail on type mismatch
+					If Not ModuleScope().IsSuperStrict() Then
+						' we have the option of upgrading our return type to match superstrict parent
+						If opt_strictupgrade And strictVoidToInt Then
+							retType = TType.voidType
+						Else
+							' otherwise...
+							voidReturnTypeFail = True
+						End If
+					End If
+				End If
+
+				If EqualsFunc( decl ) And Not voidReturnTypeFail
+
+					' check we aren't attempting to assign weaker access modifiers
+					If (IsProtected() And decl.IsPublic()) Or (IsPrivate() And (decl.IsProtected() Or decl.IsPublic())) Then
+					
+						Err PrivilegeError(Self, decl)
+					
+					End If
+				
+					If (TObjectType(retType) And TObjectType(decl.retType )) Or (TArrayType(retType) And TArrayType(decl.retType)) Then
+						If Not retType.EqualsType( decl.retType ) And retType.ExtendsType( decl.retType ) Then
+							returnTypeSubclassed = True
+						End If
+					End If
+					
+					overrides=TFuncDecl( decl.actual )
+				Else
+					' method overloading?
+					If Not EqualsArgs(decl) Then
+						found = False
+						Continue
+					End If
+					
+					'prepare a more detailed error message
+					If (Not retType.EqualsType( decl.retType ) Or Not retType.ExtendsType( decl.retType )) Or (decl.retType And Not decl.retType.EqualsType( retType )) Or voidReturnTypeFail
+						errorDetails :+ "Return type is ~q"+retType.ToString()+"~q, expected ~q"+decl.retType.ToString()+"~q. "
+						If voidReturnTypeFail Then
+							errorDetails :+ "You may have Strict type overriding SuperStrict type. "
+						End If
+					Else
+						found = False
+						Continue
+					End If
+
+					Local argCount:Int = Min(argDecls.Length, decl.argDecls.Length)
+					If argCount > 0
+						For Local i:Int=0 Until argCount
+							If Not argDecls[i].ty.EqualsType( decl.argDecls[i].ty )
+								errorDetails :+ "Argument #"+(i+1)+" is ~q" + argDecls[i].ty.ToString()+"~q, expected ~q"+decl.argDecls[i].ty.ToString()+"~q. "
+							End If
+						Next
+					EndIf
+					'remove last space
+					errorDetails = errorDetails.Trim()
+				EndIf
+			End If
+		Next
+		Return found
+	End Method
 
 	Method CheckAccess:Int()
 		If ModuleScope() = _env.ModuleScope() Return True

+ 11 - 1
options.bmx

@@ -25,7 +25,7 @@ SuperStrict
 
 Import "base.configmap.bmx"
 
-Const version:String = "0.100"
+Const version:String = "0.101"
 
 Const BUILDTYPE_APP:Int = 0
 Const BUILDTYPE_MODULE:Int = 1
@@ -116,6 +116,12 @@ Global opt_head:Int = False
 Global opt_nohead:Int = False
 ' makelib
 Global opt_makelib:Int = False
+' override
+'    require override keyword
+Global opt_require_override:Int = False
+' overerr
+'    missing override is error
+Global opt_override_error:Int = False
 
 Global opt_filepath:String
 
@@ -217,6 +223,10 @@ Function ParseArgs:String[](args:String[])
 				opt_nohead=True
 			Case "makelib"
 				opt_makelib=True
+			Case "override"
+				opt_require_override=True
+			Case "overerr"
+				opt_override_error=True
 		End Select
 	
 		count:+ 1

+ 7 - 0
parser.bmx

@@ -2751,6 +2751,13 @@ End Rem
 			
 			attrs:|DECL_ABSTRACT
 		End If
+		
+		If CParse("override") Then
+			If Not classDecl Then
+				Err "Override cannot be used with global functions"
+			End If
+			attrs :| DECL_OVERRIDE
+		End If
 			
 		If CParse( "nodebug" ) Then
 			attrs :| DECL_NODEBUG

+ 1 - 1
toker.bmx

@@ -49,7 +49,7 @@ Type TToker
 		"and,or,shl,shr,sar,end,if,then,else,elseif,endif,while,wend,repeat,until,forever,for,to,step," + ..
 		"next,return,alias,rem,endrem,throw,assert,try,catch,finally,nodebug,incbin,endselect,endmethod," + ..
 		"endfunction,endtype,endextern,endtry,endwhile,pi,release,defdata,readdata,restoredata,interface," + ..
-		"endinterface,implements,size_t,uint,ulong,struct,endstruct,operator,where,readonly,export"
+		"endinterface,implements,size_t,uint,ulong,struct,endstruct,operator,where,readonly,export,override"
 	Global _keywords:TMap
 
 	Field _path$