Kaynağa Gözat

Enums. Initial support.

woollybah 6 yıl önce
ebeveyn
işleme
1bb0b63c34
7 değiştirilmiş dosya ile 305 ekleme ve 6 silme
  1. 31 0
      ctranslator.bmx
  2. 98 0
      decl.bmx
  3. 54 2
      expr.bmx
  4. 62 0
      parser.bmx
  5. 2 1
      toker.bmx
  6. 1 0
      translator.bmx
  7. 57 3
      type.bmx

+ 31 - 0
ctranslator.bmx

@@ -284,6 +284,7 @@ Type TCTranslator Extends TTranslator
 		End If
 
 		If TExternObjectType( ty ) Return "struct " + TExternObjectType( ty ).classDecl.munged + p
+		If TEnumType( ty ) Return TransType( TEnumType( ty ).decl.ty, ident ) + p
 
 		InternalErr "TCTranslator.TransType"
 	End Method
@@ -363,6 +364,9 @@ Type TCTranslator Extends TTranslator
 			Return t
 		End If
 		If TExternObjectType( ty ) Return ":" + TExternObjectType(ty).classDecl.ident + p
+		If TEnumType( ty ) Then
+			Return "/" + TEnumType( ty ).decl.ident + p
+		End If
 		InternalErr "TCTranslator.TransIfcType"
 	End Method
 
@@ -423,6 +427,7 @@ Type TCTranslator Extends TTranslator
 			End If
 			If TStringType( ty ) Return TransStringConst(value )
 			If TByteType( ty ) Return value
+			If TEnumType( ty ) Return value
 		Else
 			If TBoolType( ty ) Return "0"
 			If TIntrinsicType( ty) Then
@@ -447,6 +452,7 @@ Type TCTranslator Extends TTranslator
 				End If
 			End If
 			If TFunctionPtrType( ty) Return "&brl_blitz_NullFunctionError" ' todo ??
+			If TEnumType( ty ) Return TEnumType( ty ).decl.values[0].Value()
 		EndIf
 		InternalErr "TCTranslator.TransValue"
 	End Method
@@ -556,6 +562,10 @@ Type TCTranslator Extends TTranslator
 						t:+ "0"
 						Continue
 					End If
+				Else If TEnumType(ty) And (ty._flags & TType.T_VAR) Then
+					If (TVarExpr(arg) Or TMemberVarExpr(arg)) And TEnumType(arg.exprType) And Not (arg.exprType._flags & TType.T_VAR) Then
+						t:+ "&"
+					End If
 				End If
 				
 				If decl.argDecls[i].castTo Then
@@ -1794,6 +1804,7 @@ t:+"NULLNULLNULL"
 			If TWParamType( src ) Return Bra("(BBINT)"+t)
 			If TLParamType( src ) Return Bra("(BBINT)"+t)
 			If TStringType( src ) Return "bbStringToInt" + Bra(t)
+			If TEnumType( src) Return Bra("(BBINT)"+t)
 			'If TIntVarPtrType( src ) Return Bra("*" + t)
 			If IsPointerType(src,0,TType.T_POINTER) Return Bra("(BBINT)"+t)
 			'If TPointerType( src ) Return Bra("(BBINT)"+t)
@@ -1813,6 +1824,7 @@ t:+"NULLNULLNULL"
 			If TStringType( src ) Return "bbStringToLong" + Bra(t)
 			If IsPointerType(src,0,TType.T_POINTER) Return Bra("(BBLONG)"+t)
 			If TFloat64Type( src ) Return Bra("(BBLONG)"+t)
+			If TEnumType( src) Return Bra("(BBLONG)"+t)
 			'If TPointerType( src ) Return Bra("(BBLONG)"+t)
 		 Else If TSizeTType( dst )
 			If TBoolType( src ) Return Bra( t )
@@ -1830,6 +1842,7 @@ t:+"NULLNULLNULL"
 			If TStringType( src ) Return "bbStringToSizet" + Bra(t)
 			If IsPointerType(src,0,TType.T_POINTER) Return Bra("(BBSIZET)"+t)
 			If TFloat64Type( src ) Return Bra("(BBSIZET)"+t)
+			If TEnumType( src) Return Bra("(BBSIZET)"+t)
 			'If TPointerType( src ) Return Bra("(BBLONG)"+t)
 		Else If TFloatType( dst )
 			If TBoolType( src ) Return Bra( t )
@@ -1892,6 +1905,16 @@ t:+"NULLNULLNULL"
 				End If
 				Return t
 			End If
+			If TEnumType( src ) Then
+				Local ty:TType = TEnumType( src ).decl.ty
+				If TByteType( ty ) Return "bbStringFromInt"+Bra( t )
+				If TShortType( ty ) Return "bbStringFromInt"+Bra( t )
+				If TIntType( ty ) Return "bbStringFromInt"+Bra( t )
+				If TUIntType( ty ) Return "bbStringFromUInt"+Bra( t )
+				If TLongType( ty ) Return "bbStringFromLong"+Bra( t )
+				If TULongType( ty ) Return "bbStringFromULong"+Bra( t )
+				If TSizeTType( ty ) Return "bbStringFromSizet"+Bra( t )
+			End If
 			'If TStringVarPtrType( src ) Then
 			'	If TSliceExpr( expr.expr ) Then
 			'		Return t
@@ -1915,6 +1938,7 @@ t:+"NULLNULLNULL"
 			If TWParamType( src ) Return Bra("(BBBYTE)"+t)
 			If TLParamType( src ) Return Bra("(BBBYTE)"+t)
 			If TStringType( src ) Return "bbStringToInt" + Bra(t)
+			If TEnumType( src) Return Bra("(BBYTE)"+t)
 			'If TByteVarPtrType( src ) Return Bra("*" + t)
 		Else If TShortType( dst )
 			If TBoolType( src ) Return Bra( t )
@@ -1930,6 +1954,7 @@ t:+"NULLNULLNULL"
 			If TWParamType( src ) Return Bra("(BBSHORT)"+t)
 			If TLParamType( src ) Return Bra("(BBSHORT)"+t)
 			If TStringType( src ) Return "bbStringToInt" + Bra(t)
+			If TEnumType( src) Return Bra("(BBSHORT)"+t)
 			'If TShortVarPtrType( src ) Return Bra("*" + t)
 		Else If TUIntType( dst )
 			If TBoolType( src ) Return Bra( t )
@@ -1945,6 +1970,7 @@ t:+"NULLNULLNULL"
 			If TWParamType( src ) Return Bra("(BBUINT)"+t)
 			If TLParamType( src ) Return Bra("(BBUINT)"+t)
 			If TStringType( src ) Return "bbStringToUInt" + Bra(t)
+			If TEnumType( src) Return Bra("(BBUINT)"+t)
 		Else If TULongType( dst )
 			If TBoolType( src ) Return Bra( t )
 			If TShortType( src ) Return Bra("(BBULONG)"+t)
@@ -1960,6 +1986,7 @@ t:+"NULLNULLNULL"
 			If TLParamType( src ) Return Bra("(BBULONG)"+t)
 			If TStringType( src ) Return "bbStringToULong" + Bra(t)
 			If TFloat64Type( src ) Return Bra("(BBULONG)"+t)
+			If TEnumType( src) Return Bra("(BBULONG)"+t)
 		Else If TFloat64Type( dst )
 			If TFloat64Type( src) Return t
 			If TLongType( src ) Return Bra("(BBFLOAT64)"+t)
@@ -2044,6 +2071,8 @@ t:+"NULLNULLNULL"
 					Return "" ' TODO??
 				End If
 			End If
+		Else If TEnumType( dst )
+			If TEnumType( src) Return t			
 		End If
 
 		Return TransPtrCast( dst,src,t,"dynamic" )
@@ -4807,6 +4836,8 @@ End Rem
 			s = variable + ind + decl.munged + " "
 		Else If TArrayType(decl.ty) Then
 			s = variable + ind + decl.munged + " "
+		Else If TEnumType(decl.ty) Then
+			s = variable + ind + decl.munged + " "
 		End If
 
 		Return s

+ 98 - 0
decl.bmx

@@ -1203,6 +1203,10 @@ Type TScopeDecl Extends TDecl
 				End If
 				Return cdecl.objectType
 			EndIf
+			Local edecl:TEnumDecl = TEnumDecl(decl)
+			If edecl Then
+				Return New TEnumType.Create(edecl)
+			End If
 		EndIf
 		If scope Return scope.FindType( ident,args, callback )
 	End Method
@@ -3433,6 +3437,100 @@ Type TTryStmtDecl Extends TBlockDecl
 	End Method
 End Type
 
+Type TEnumDecl Extends TScopeDecl
+	Field ty:TType
+	Field isFlags:Int
+	Field values:TEnumValueDecl[]
+	
+	Method Create:TEnumDecl(id:String, ty:TType, isFlags:Int, values:TEnumValueDecl[])
+		Self.ident = id
+		Self.ty = ty
+		Self.isFlags = isFlags
+		Self.values = values
+		Return Self
+	End Method
+	
+	Method OnSemant()
+		' validate type
+		If Not TIntegralType(ty) Then
+			Err "Invalid type '" + ty.ToString() + "'. Enums can only be declared with integral types."
+		End If
+		
+		For Local val:TEnumValueDecl = EachIn values
+			val.scope = Self
+			val.Semant()
+		Next
+	End Method
+
+	Method OnCopy:TDecl(deep:Int = True)
+		Return New TEnumDecl.Create(ident, ty, isFlags, values)
+	End Method
+	
+	Method GetDecl:Object( ident$ )
+		For Local val:TEnumValueDecl = EachIn values
+			If val.IdentLower() = ident And val.IsSemanted() Then
+				Return val
+			End If
+		Next
+	End Method
+	
+	Method ToString:String()
+		Return ident
+	End Method
+End Type
+
+Type TEnumValueDecl Extends TDecl
+
+	Field expr:TExpr
+	Field ordinal:Int
+	
+	Field generatedValue:Int
+	
+	Method Create:TEnumValueDecl(id:String, ordinal:Int, expr:TExpr)
+		Self.ident = id
+		Self.ordinal = ordinal
+		Self.expr = expr
+		Return Self
+	End Method
+
+	Method OnSemant()
+		Local parent:TEnumDecl = TEnumDecl(scope)
+		Local previous:TEnumValueDecl
+		If ordinal > 0 Then
+			previous = parent.values[ordinal - 1]
+		End If
+
+		If expr Then
+			expr = expr.Semant()
+			
+			If Not TConstExpr(expr) Or Not TIntegralType(TConstExpr(expr).ty) Then
+				Err "Enum values must be integral constants."
+			End If
+		Else
+			Local val:Long = ordinal
+			If previous Then
+				val = TConstExpr(previous.expr).value.ToLong() + 1
+			End If
+
+			expr = New TConstExpr.Create( parent.ty.Copy(), val).Semant()
+			generatedValue = True
+		
+		End If
+	End Method
+
+	Method OnCopy:TDecl(deep:Int = True)
+		Return New TEnumValueDecl.Create(ident, ordinal, expr)
+	End Method
+	
+	Method Value:String()
+		Return TConstExpr(expr).value
+	End Method
+	
+	Method ToString:String()
+		Return "TEnumValueDecl"
+	End Method
+End Type
+
 Const MODULE_STRICT:Int=1
 Const MODULE_SUPERSTRICT:Int=2
 Const MODULE_ACTUALMOD:Int=4

+ 54 - 2
expr.bmx

@@ -263,6 +263,10 @@ Type TExpr
 		If TLongType( lhs ) Or TLongType( rhs ) Return New TLongType
 		If TUIntType( lhs ) Or TUIntType( rhs ) Return New TUIntType
 		If TIntType( lhs ) Or TIntType( rhs ) Return New TIntType
+		If TEnumType( lhs ) Or TEnumType( rhs ) Then
+			If TEnumType( lhs ) Return lhs
+			If TEnumType( rhs ) Return rhs
+		End If
 		If TObjectType( lhs ) And TNullDecl(TObjectType( lhs ).classDecl) Then
 			Return rhs
 		End If
@@ -1545,6 +1549,20 @@ Type TCastExpr Extends TExpr
 			Return Self
 		End If
 
+		If TStringType(ty) And TEnumType(src) Then
+			exprType = ty
+			Return Self
+		End If
+
+		If TEnumType(src) And TEnumType(ty) And (ty._flags & TType.T_VAR) Then
+			Return expr
+		End If
+		
+		If TIntegralType(ty) And TEnumType(src) And flags & CAST_EXPLICIT Then
+			exprType = ty
+			Return Self
+		End If
+
 		If Not exprType
 			Err "Unable to convert from "+src.ToString()+" to "+ty.ToString()+"."
 		EndIf
@@ -2722,15 +2740,22 @@ Type TIdentExpr Extends TExpr
 
 			Return New TInvokeExpr.Create( fdecl,args, False, isArg, isRhs ).Semant()
 		End If
-		
+
+		Local decl:TDecl = TDecl(scope.FindDecl(IdentLower()))
 		' maybe it's a classdecl?
-		Local cdecl:TClassDecl = TClassDecl(scope.FindDecl(IdentLower()))
+		Local cdecl:TClassDecl = TClassDecl(decl)
 		
 		If cdecl Then
 			Local e:TIdentTypeExpr = New TIdentTypeExpr.Create(cdecl.objectType)
 			e.cdecl = cdecl
 			Return e
 		End If
+		
+		' maybe it's an enum?
+		Local edecl:TEnumValueDecl = TEnumValueDecl(decl)
+		If edecl Then
+			Return New TIdentEnumExpr.Create(edecl)
+		End If
 
 		Local loopLabel:String = "#" + IdentLower()
 
@@ -3295,3 +3320,30 @@ Type TDataLabelExpr Extends TExpr
 	End Method
 
 End Type
+
+Type TIdentEnumExpr Extends TExpr
+	Field value:TEnumValueDecl
+
+	Method Create:TIdentEnumExpr( value:TEnumValueDecl )
+		Self.exprType=New TEnumType.Create(TEnumDecl(value.scope))
+		Self.value = value
+		Return Self
+	End Method
+
+	Method Copy:TExpr()
+		Return New TIdentEnumExpr.Create( value )
+	End Method
+
+	Method Semant:TExpr()
+		Return Self
+	End Method
+
+	Method Trans$()
+		Return value.Value()
+	End Method
+
+	Method Eval$()
+		Return value.Value()
+	End Method
+
+End Type

+ 62 - 0
parser.bmx

@@ -2973,6 +2973,66 @@ End Rem
 		Return args
 	End Method
 	
+	Method ParseEnumDecl:TEnumDecl( toke:String )
+		SetErr
+
+		If toke Parse toke
+
+		Local id:String = ParseIdent()
+		Local ty:TType = ParseConstNumberType()
+
+		If Not ty Then
+			ty = New TIntType
+		End If
+
+		Local isFlags:Int = 0
+		Local values:TEnumValueDecl[0]
+		
+		If CParse("flags")
+			isFlags = True
+		End If
+		
+		Local decl:TEnumDecl = New TEnumDecl.Create(id, ty, isFlags, values)
+
+		Local nValues:Int
+		
+		Repeat
+		
+			SkipEols
+
+			If CParse("end") Then
+				Parse("enum")
+				Exit
+			End If
+			
+			If CParse("endenum") Then
+				Exit
+			End If
+			
+			Local valId:String = ParseIdent()
+			Local value:TExpr
+			
+			If CParse( "=" ) Then
+				value = ParseExpr()
+			End If
+			
+			Local v:TEnumValueDecl = New TEnumValueDecl.Create(valId, nValues, value)
+			If decl.values.Length = nValues Then
+				decl.values = decl.values + New TEnumValueDecl[10]
+			End If
+
+			decl.values[nValues] = v
+			nValues :+ 1
+			
+			CParse(",")
+		
+		Forever
+
+		decl.values = decl.values[..nValues]
+
+		Return decl
+		
+	End Method
 
 	Method ParseClassDecl:TClassDecl( toke$,attrs:Int, templateDets:TTemplateDets = Null )
 		SetErr
@@ -3686,6 +3746,8 @@ End Rem
 				_module.InsertDecl ParseClassDecl( _toke,attrs)
 			Case "interface"
 				_module.InsertDecl ParseClassDecl( _toke,attrs|CLASS_INTERFACE|DECL_ABSTRACT )
+			Case "enum"
+				_module.InsertDecl ParseEnumDecl( _toke )
 			Case "function"
 				_module.InsertDecl ParseFuncDecl( _toke,attrs )
 			Case "incbin"

+ 2 - 1
toker.bmx

@@ -49,7 +49,8 @@ Type TToker
 		"and,or,shl,shr,sar,end,if,then,else,elseif,endif,while,wend,repeat,until,forever,for,to,step,goto," + ..
 		"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,override"
+		"endinterface,implements,size_t,uint,ulong,struct,endstruct,operator,where,readonly,export,override," + ..
+		"enum,endenum"
 	Global _keywords:TMap
 
 	Field _path$

+ 1 - 0
translator.bmx

@@ -268,6 +268,7 @@ Type TTranslator
 '			Next
 			Return s + "_" + TransMangleType(func.retType) + "_"
 		End If
+		If TEnumType( ty ) Return p + "e" + TEnumType( ty ).decl.ident
 		
 		Err "Unsupported type for name mangling : " + ty.ToString()
 	End Method

+ 57 - 3
type.bmx

@@ -210,6 +210,7 @@ Type TType
 	Const T_DOUBLE128:Int   = $8000
 	Const T_LPARAM:Int      =$10000
 	Const T_WPARAM:Int      =$20000
+	Const T_ENUM:Int        =$40000
 
 	Const T_MAX_DISTANCE:Int = $FFFF
 
@@ -276,6 +277,8 @@ Function NewType:TType(kind:Int = 0)
 			ty = New TArrayType
 		Case TType.T_FUNCTIONPTR
 			ty = New TFunctionPtrType
+		Case TType.T_ENUM
+			ty = New TEnumType
 		Default
 			Err "Don't have a pointer type for " + kind
 	End Select
@@ -341,6 +344,8 @@ Function IsType:Int(ty:TType, kind:Int)
 			Return TArrayType(ty) <> Null
 		Case TType.T_FUNCTIONPTR
 			Return TFunctionPtrType(ty) <> Null
+		Case TType.T_ENUM
+			Return TEnumType(ty) <> Null
 	End Select
 
 	Return False
@@ -1634,9 +1639,14 @@ Type TIdentType Extends TType
 			Err "Type '"+tyid+"' not found"
 		End If
 		
-		If (_flags & T_VAR) And TObjectType(ty) Then
-			ty = New TObjectType.Create(TObjectType(ty).classDecl)
-			ty._flags :| T_VAR
+		If (_flags & T_VAR) Then
+			If TObjectType(ty) Then
+				ty = New TObjectType.Create(TObjectType(ty).classDecl)
+				ty._flags :| T_VAR
+			Else If TEnumType(ty) Then
+				ty = New TEnumType.Create(TEnumType(ty).decl)
+				ty._flags :| T_VAR
+			End If
 		End If
 
 		If (_flags & T_POINTER) And TObjectType(ty) Then
@@ -2011,6 +2021,50 @@ Type TLParamType Extends TParamType
 
 End Type
 
+Type TEnumType Extends TType
+
+	Field decl:TEnumDecl
+	
+	Method Create:TEnumType(decl:TEnumDecl)
+		Self.decl = decl
+		Return Self
+	End Method
+
+	Method EqualsType:Int( ty:TType )
+		Local ety:TEnumType = TEnumType(ty)
+		Return ety And decl = ety.decl And(_flags = ty._flags Or ..
+			(_flags & T_VARPTR And ty._flags & T_PTR) Or (ty._flags & T_VARPTR And _flags & T_PTR) Or (_flags & T_VAR))
+	End Method
+
+	Method ExtendsType:Int( ty:TType, noExtendString:Int = False, widensTest:Int = False )
+		If _flags & T_VARPTR And (TEnumType(ty) <> Null Or IsPointerType(ty, 0, T_POINTER)) Return True
+		Return (widensTest And WidensToType(ty)) Or (Not noExtendString And TStringType( ty )<>Null)
+	End Method
+
+	Method WidensToType:Int( ty:TType )
+		Return (IsPointerType(ty, 0, T_POINTER) And IsPointerType(Self, 0, T_POINTER)) Or (TEnumType(ty)<>Null And (ty._flags & T_VAR))
+	End Method
+	
+	Method OnCopy:TType()
+		Local ty:TEnumType = New TEnumType
+		ty.decl = decl
+		Return ty
+	End Method
+	
+	Method IsFlags:Int()
+		Return decl.isFlags
+	End Method
+	
+	Method Value:String(ordinal:Int)
+		Return decl.values[ordinal].Value()
+	End Method
+
+	Method ToString$()
+		Return "Enum " + decl.ident + " " + ToStringParts()
+	End Method
+
+End Type
+
 Type TTemplateArg
 	Field ident:String
 	Field superTy:TType[]