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

Cleanups, bugfixes, docs etc.

blitz-research 9 жил өмнө
parent
commit
3065fee7e5

+ 3 - 0
bin/env_linux.txt

@@ -1,6 +1,9 @@
 
 '***** COMMON *****
 
+MX2_VERSION=002
+MX2_BUILDV=002
+
 MX2_BUILD_VERBOSE=0
 
 '***** DESKTOP *****

+ 3 - 0
bin/env_macos.txt

@@ -1,6 +1,9 @@
 
 '***** COMMON *****
 
+MX2_VERSION=002
+MX2_BUILDV=002
+
 MX2_BUILD_VERBOSE=0
 
 '***** DESKTOP *****

+ 3 - 0
bin/env_windows.txt

@@ -1,6 +1,9 @@
 
 '***** COMMON ******
 
+MX2_VERSION=002
+MX2_BUILDV=002
+
 MX2_BUILD_VERBOSE=0
 
 '***** DESKTOP *****

BIN
bin/mx2cc_linux


BIN
bin/mx2cc_macos


BIN
bin/mx2cc_windows.exe


+ 27 - 2
modules/libc/libc.monkey2

@@ -54,7 +54,32 @@ Function memmove:Void Ptr( dst:Void Ptr,src:Void Ptr,length:Int )
 
 '***** time.h *****
 
-Alias time_t:Long
+Struct time_t
+End
+
+Struct tm_t
+	Field tm_sec:Int
+	Field tm_min:Int
+	Field tm_hour:Int
+	Field tm_mday:Int
+	Field tm_mon:Int
+	Field tm_year:Int
+	Field tm_wday:Int
+	Field tm_yday:Int
+	Field tm_isdst:Int
+End
+
+Const CLOCKS_PER_SEC:Long="((bbLong)CLOCKS_PER_SEC)"
+
+Function clock:Long()="(bbLong)clock"
+
+'dodgy!
+Function tolong:long( timer:time_t )="bbLong"
+
+Function time:time_t( timer:time_t Ptr )
+Function localtime:tm_t Ptr( timer:time_t Ptr )
+Function gmtime:tm_t Ptr( timer:time_t Ptr )
+Function difftime:Double( endtime:time_t,starttime:time_t ) 
 
 '***** unistd.h *****
 
@@ -67,7 +92,7 @@ Function rmdir:Int( path:CString )
 Enum mode_t
 End
 
-Const S_IFMT:mode_t	'$f000
+Const S_IFMT:mode_t		'$f000
 Const S_IFIFO:mode_t	'$1000
 Const S_IFCHR:mode_t	'$2000
 Const S_IFBLK:mode_t	'$3000

+ 3 - 0
modules/libc/native/libc.h

@@ -9,6 +9,7 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <dirent.h>
+#include <time.h>
 
 #if _WIN32
 #include <direct.h>
@@ -22,4 +23,6 @@ int system_( const char *command );
 void setenv_( const char *name,const char *value,int overwrite );
 int mkdir_( const char *path,int mode );
 
+typedef struct tm tm_t;
+
 #endif

+ 14 - 14
modules/monkey/native/bbtypes.cpp

@@ -33,29 +33,19 @@ namespace{
 		bbString name;
 		
 		const char *p0=p;
+
 		for( ;; ){
 		
-			if( !*p || *p=='E' ){
-
-				name+=bbString( p0,p-p0 );
-				if( *p ) ++p;
-				return name;
-			}
+			if( !*p ) return name+bbString( p0,p-p0 );
 			
 			if( *p++!='_' ) continue;
 			
 			name+=bbString( p0,p-p0-1 );
 			
-			if( *p<'0' || *p>'9' ){
-				name+=".";
-				p0=p;
-				continue;
-			}
-			
-			int c=*p++;
+			char c=*p++;
 			
 			if( c=='0' ){
-
+			
 				name+="_";
 				
 			}else if( c=='1' ){
@@ -68,6 +58,16 @@ namespace{
 				name+="<"+types+">";
 				if( !*p ) return name;
 				++p;
+				
+			}else if( c=='2' ){
+			
+				return name;
+				
+			}else{
+			
+				name+=".";
+				p0=p-1;
+				continue;
 			}
 			
 			p0=p;

+ 13 - 9
modules/std/container.monkey2

@@ -5,17 +5,20 @@ Namespace std
 #end
 Interface IContainer<T>
 
-	Property Empty:Bool()
+	'Property Empty:Bool()
 	
 	'Method All:IIterator<T>()
+
+	'Method Find:IIterator<T>( value:T ) Default...
+
 	
 	'For sequences...
 	
-	Method Add( value:T )
+	'Method Add( value:T )
 	
-	Method AddAll( value:T[] )
+	'Method AddAll( value:T[] ) Default...
 	
-	'Method AddAll<C>( values:C ) Where C Implements IContainer<T>
+	'Method AddAll<C>( values:C ) Where C Implements IContainer<T> Default...
 	
 End
 
@@ -23,16 +26,17 @@ End
 #end
 Interface IIterator<T>
 
-	Property Valid:Bool()
+	'Property Valid:Bool()
+	
+	'Property Current:T()
 	
-	Property Current:T()
+	'Method Bump()
 	
-	Method Bump()
 	
 	'For sequences...
 	
-	Method Erase()
+	'Method Erase()
 	
-	Method Insert( value:T )
+	'Method Insert( value:T )
 	
 End

+ 2 - 2
modules/std/filesystem.monkey2

@@ -168,7 +168,7 @@ Function RealPath:String( path:String )
 	Return rpath
 End
 
-Function FileTime:Long( path:String )
+Function FileTime:long( path:String )
 
 	path=StripSlashes( path )
 
@@ -176,7 +176,7 @@ Function FileTime:Long( path:String )
 	
 	If stat( path,Varptr st )<0 Return 0
 	
-	Return st.st_mtime
+	Return libc.tolong( st.st_mtime )
 End
 
 Function FileType:Int( path:String )

+ 27 - 29
modules/std/filesystemex.monkey2

@@ -8,7 +8,7 @@ Using libc
 
 Extern
 
-Function AppDirectory:String()="bbFileSystem::appDir"
+Function AppDir:String()="bbFileSystem::appDir"
 Function AppPath:String()="bbFileSystem::appPath"
 Function AppArgs:String[]()="bbFileSystem::appArgs"
 Function CopyFile:Bool( srcPath:String,dstPath:String )="bbFileSystem::copyFile"
@@ -27,12 +27,12 @@ End
 @return The directory app assets are stored in.
 
 #end
-Function AssetsDirectory:String()
+Function AssetsDir:String()
 
 #If __TARGET__="desktop" And __HOSTOS__="macos"
-	Return AppDirectory()+"../Resources/"
+	Return AppDir()+"../Resources/"
 #Else
-	Return AppDirectory()+"assets/"
+	Return AppDir()+"assets/"
 #Endif
 
 End
@@ -44,7 +44,7 @@ End
 @return The root directory of `path`, or an empty string if `path` is not an absolute path.
  
 #end
-Function GetRootDirectory:String( path:String )
+Function GetRootDir:String( path:String )
 
 	If path.StartsWith( "//" ) Return "//"
 	
@@ -73,7 +73,7 @@ End
 @return True if `path` is a root directory path.
 
 #end
-Function IsRootDirectory:Bool( path:String )
+Function IsRootDir:Bool( path:String )
 
 	If path="//" Return True
 	
@@ -105,7 +105,7 @@ An absolute path is a path that begins with a root directory.
 #end
 Function IsAbsolutePath:Bool( path:String )
 
-	Return GetRootDirectory( path )<>""
+	Return GetRootDir( path )<>""
 End
 
 #rem monkeydoc Strips any trailing slashes from a filesystem path.
@@ -121,7 +121,7 @@ Function StripSlashes:String( path:String )
 
 	If Not path.EndsWith( "/" ) Return path
 	
-	Local root:=GetRootDirectory( path )
+	Local root:=GetRootDir( path )
 	
 	Repeat
 	
@@ -145,10 +145,10 @@ If `path` does not contain a parent directory, an empty string is returned.
 @return The parent directory of `path`.
 
 #end
-Function GetParentDirectory:String( path:String )
+Function GetParentDir:String( path:String )
 
 	path=StripSlashes( path )
-	If IsRootDirectory( path ) Return path
+	If IsRootDir( path ) Return path
 	
 	Local i:=path.FindLast( "/" )
 	If i>=0 Return path.Slice( 0,i+1 )
@@ -167,10 +167,10 @@ If `path` does not contain a parent directory, `path` is returned without modifi
 @return `path` with the parent directory stripped.
 
 #end
-Function StripParentDirectory:String( path:String )
+Function StripParentDir:String( path:String )
 
 	path=StripSlashes( path )
-	If IsRootDirectory( path ) Return ""
+	If IsRootDir( path ) Return ""
 
 	Local i:=path.FindLast( "/" )
 	If i>=0 Return path.Slice( i+1 )
@@ -227,23 +227,21 @@ Function GetAbsolutePath:String( path:String )
 	
 	If IsAbsolutePath( path ) Return path
 	
-	Return GetCurrentDirectory()+path
+	Return CurrentDir()+path
 End
 
 #rem monkeydoc Converts a relative path to a real path.
 
 A real path is a path with any internal './' or '../' references collapsed.
 
-If `path` is a relative path, it is first converted to an absolute path relative to the current directory.
-
 @param path The filesystem path.
 
-@param The path with any './', '../' components collapsed.
+@param The path with any './', '../' references collapsed.
 
 #end
 Function GetRealPath:String( path:String )
 
-	Local rpath:=GetRootDirectory( path )
+	Local rpath:=GetRootDir( path )
 	If rpath path=path.Slice( rpath.Length )
 	
 	While path
@@ -255,8 +253,8 @@ Function GetRealPath:String( path:String )
 		Case ""
 		Case "."
 		Case ".."
-			If Not rpath rpath=GetCurrentDirectory()
-			rpath=GetParentDirectory( rpath )
+			If Not rpath rpath=CurrentDir()
+			rpath=GetParentDir( rpath )
 		Default
 			rpath+=t+"/"
 		End
@@ -279,7 +277,7 @@ Function GetFileTime:Long( path:String )
 	Local st:stat_t
 	If stat( path,Varptr st )<0 Return 0
 	
-	Return st.st_mtime
+	Return libc.tolong( st.st_mtime )
 End
 
 #rem monkeydoc Gets the type of the file at a filesystem path.
@@ -309,7 +307,7 @@ End
 @return The current directory for the running process.
 
 #end
-Function GetCurrentDirectory:String()
+Function CurrentDir:String()
 
 	Local sz:=4096
 	Local buf:=Cast<CChar Ptr>( malloc( sz ) )
@@ -327,7 +325,7 @@ End
 @param path The file system directory to make current.
 
 #end
-Function SetCurrentDirectory( path:String )
+Function ChangeDir( path:String )
 
 	path=StripSlashes( path )
 	
@@ -341,7 +339,7 @@ End
 @return An array containing all filenames in the `path`, excluding '.' and '..' entries.
 
 #end
-Function LoadDirectory:String[]( path:String )
+Function LoadDir:String[]( path:String )
 
 	path=StripSlashes( path )
 
@@ -374,16 +372,16 @@ End
 @return True if a directory at `path` was successfully created or already existed.
 
 #end
-Function CreateDirectory:Bool( path:String,recursive:Bool=True )
+Function CreateDir:Bool( path:String,recursive:Bool=True )
 
 	path=StripSlashes( path )
 
 	If recursive
-		Local parent:=GetParentDirectory( path )
-		If parent And Not IsRootDirectory( parent )
+		Local parent:=GetParentDir( path )
+		If parent And Not IsRootDir( parent )
 			Select GetFileType( parent )
 			Case FileType.None
-				If Not CreateDirectory( parent,True ) Return False
+				If Not CreateDir( parent,True ) Return False
 			Case FileType.File
 				Return False
 			Case FileType.Directory
@@ -410,7 +408,7 @@ Function DeleteAll:Bool( path:String )
 		
 	Case FileType.Directory
 	
-		For Local f:=Eachin LoadDirectory( path )
+		For Local f:=Eachin LoadDir( path )
 			If Not DeleteAll( path+"/"+f ) Return False
 		Next
 		
@@ -432,7 +430,7 @@ Public
 @return True if the directory was successfully deleted or never existed.
 
 #end
-Function DeleteDirectory:Bool( path:String,recursive:Bool=False )
+Function DeleteDir:Bool( path:String,recursive:Bool=False )
 
 	path=StripSlashes( path )
 

+ 98 - 17
modules/std/list.monkey2

@@ -87,7 +87,7 @@ Class List<T> Implements IContainer<T>
 	Field _length:Int
 	Field _seq:Int
 	
-	#rem monkeydoc Creates a new empty list
+	#rem monkeydoc Creates a new empty list.
 	#end
 	Method New()
 	End
@@ -101,6 +101,11 @@ Class List<T> Implements IContainer<T>
 		AddAll( values )
 	End
 	
+	#rem monkeydoc Gets an iterator to all values in the list.
+
+	@return A list iterator.
+	
+	#end
 	Method All:Iterator()
 		Return New Iterator( Self,_first )
 	End
@@ -111,7 +116,7 @@ Class List<T> Implements IContainer<T>
 	
 	#end
 	Property Empty:Bool()
-		Return _first=Null
+		Return _length=0
 	End
 	
 	#rem monkeydoc Gets the number of values in the list.
@@ -141,7 +146,7 @@ Class List<T> Implements IContainer<T>
 	
 	#rem monkeydoc Gets the first value in the list.
 	
-	In debug builds, if the list is empty a runtime error occurs.
+	In debug builds, a runtime error will occur if the list is empty.
 	
 	@return The first value in the list.
 	
@@ -151,9 +156,9 @@ Class List<T> Implements IContainer<T>
 		Return _first._value
 	End
 	
-	#rem monkeydoc Get the last item in a list
+	#rem monkeydoc Gets the last value in the list
 	
-	In debug builds, if the list is empty a runtime error occurs.
+	In debug builds, a runtime error will occur if the list is empty.
 	
 	@return The last value in the list.
 	
@@ -176,6 +181,8 @@ Class List<T> Implements IContainer<T>
 	#rem monkeydoc Adds a value to the start of the list.
 	
 	@param value The value to add to the list.
+	
+	@return The new node containing the value.
 
 	#end
 	Method AddFirst( value:T )
@@ -209,15 +216,16 @@ Class List<T> Implements IContainer<T>
 		_seq+=1
 	End
 	
-	#rem monkeydoc Removes the first item in the list and returns it.
+	#rem monkeydoc Removes and returns the first value in the list.
 	
-	In debug builds, if the list is empty a runtime error occurs.
+	In debug builds, a runtime error will occur if the list is empty.
 	
-	@return The first item in the list before the method was called.
+	@return The value removed from the list.
 
 	#end
 	Method RemoveFirst:T()
-		DebugAssert( Not Empty )
+		DebugAssert( _length )
+		
 		Local value:=_first._value
 		_first=_first._succ
 		If _first _first._pred=Null Else _last=Null
@@ -226,15 +234,16 @@ Class List<T> Implements IContainer<T>
 		Return value
 	End
 	
-	#rem monkeydoc Removes the last value in the list and returns it.
+	#rem monkeydoc Removes and returns the last value in the list.
 	
-	In debug builds, if the list is empty a runtime error occurs.
+	In debug builds, a runtime error will occur if the list is empty.
 	
-	@return The last item in the list before the method was called.
+	@return The value removed from the list.
 
 	#end
 	Method RemoveLast:T()
-		DebugAssert( Not Empty )
+		DebugAssert( _length )
+		
 		Local value:=_last._value
 		_last=_last._pred
 		If _last _last._succ=Null Else _first=Null
@@ -243,20 +252,82 @@ Class List<T> Implements IContainer<T>
 		Return value
 	End
 	
-	#rem monkedoc Removes all values in the list equal to a given value.
+	#rem monkeydoc Finds the first node in the list that contains a given value.
 	
-	@param value The value to check for equality.
+	@param value The value to find.
+	
+	@return Node The node containing the value, or null if the value was not found.
 	
 	#end
-	Method RemoveEach( value:T )
+	Method FindNode:Node( value:T )
 		Local node:=_first
+		While node And node._value<>value
+			node=node._succ
+		Wend
+		Return node
+	End
+	
+	#rem monkeydoc Finds the last node in the list that contains a given value.
+	
+	@param value The value to find.
+	
+	@return Node The node containing the value, or null if the value was not found.
+	
+	#end
+	Method FindLastNode:Node( value:T )
+		Local node:=_last
+		While node And node._value<>value
+			node=node._pred
+		Wend
+		Return node
+	End
+	
+	#rem monkeydoc Removes the first value in the list equal to a given value.
+	
+	@param value The value to remove.
+
+	@return True if a value was removed.
+		
+	#end
+	Method Remove:Bool( value:T )
+		Local node:=FindNode( value )
+		If Not node Return False
+		Erase( node )
+		Return True
+	End
+	
+	#rem monkeydoc Removes the last value in the list equal to a given value.
+	
+	@param value The value to remove.
+	
+	@return True if a value was removed.
+		
+	#end
+	Method RemoveLast:Bool( value:T )
+		Local node:=FindLastNode( value )
+		If Not node Return False
+		Erase( node )
+		Return True
+	End
+	
+	#rem monkedoc Removes all values in the list equal to a given value.
+	
+	@param value The value to remove.
+	
+	@return The number of values removed.
+	
+	#end
+	Method RemoveEach:Int( value:T )
+		Local node:=_first,n:=0
 		While node
 			If node._value=value
 				node=Erase( node )
+				n+=1
 			Else
 				node=node._succ
 			Endif
 		Wend
+		Return n
 	End
 
 	#rem monkeydoc Gets an iterator for the value at a given index in the list.
@@ -313,7 +384,17 @@ Class List<T> Implements IContainer<T>
 		Next
 	End
 
-	Private	
+	Private
+	
+	'could make these public if people REALLY want...
+	'
+	Method FirstNode:Node()
+		Return _first
+	End
+	
+	Method LastNode:Node()
+		Return _last
+	End
 	
 	Method Erase:Node( node:Node )
 		If Not node Return Null	'OK to erase tail element...

+ 182 - 39
modules/std/map.monkey2

@@ -1,10 +1,34 @@
 
 Namespace std
 
+#rem monkedoc The Map class.
+#end
 Class Map<K,V>
 
+	#rem monkeydoc The map Node class.
+	#end
 	Class Node
 	
+		#rem monkeydoc Gets the key contained in the node.
+		
+		@return The node's key.
+		
+		#end
+		Property Key:K()
+			Return _key
+		End
+		
+		#rem monkeydoc Gets the value contained in the node.
+		
+		@return The node's value.
+		
+		#end
+		Property Value:V()
+			Return _value
+		End
+	
+		Private	
+	
 		Enum Color
 			Red
 			Black
@@ -24,14 +48,6 @@ Class Map<K,V>
 			_parent=parent
 		End
 		
-		Property Key:K()
-			Return _key
-		End
-		
-		Property Value:V()
-			Return _value
-		End
-	
 		Method Count:Int( n:Int )
 			If _left n=_left.Count( n )
 			If _right n=_right.Count( n )
@@ -79,14 +95,8 @@ Class Map<K,V>
 	
 	End
 	
-	Struct MapIterator
+	Struct Iterator
 	
-		Field _node:Node
-		
-		Method New( node:Node )
-			_node=node
-		End
-		
 		Property Valid:Bool()
 			Return _node
 		End
@@ -99,16 +109,18 @@ Class Map<K,V>
 			_node=_node.NextNode()
 		End
 		
-	End
-	
-	Struct KeyIterator
-	
+		Private
+		
 		Field _node:Node
 		
 		Method New( node:Node )
 			_node=node
 		End
 		
+	End
+	
+	Struct KeyIterator
+	
 		Property Valid:Bool()
 			Return _node
 		End
@@ -121,16 +133,18 @@ Class Map<K,V>
 			_node=_node.NextNode()
 		End
 		
-	End
-	
-	Struct ValueIterator
-	
+		Private
+		
 		Field _node:Node
 		
 		Method New( node:Node )
 			_node=node
 		End
 		
+	End
+	
+	Struct ValueIterator
+	
 		Property Valid:Bool()
 			Return _node
 		End
@@ -143,75 +157,164 @@ Class Map<K,V>
 			_node=_node.NextNode()
 		End
 		
+		Private
+		
+		Field _node:Node
+		
+		Method New( node:Node )
+			_node=node
+		End
+		
 	End
 	
 	Struct MapKeys
 	
+		Method All:KeyIterator()
+			Return New KeyIterator( _map.FirstNode() )
+		End
+		
+		Private
+		
 		Field _map:Map
 		
 		Method New( map:Map )
 			_map=map
 		End
 		
-		Method Iterator:KeyIterator()
-			Return New KeyIterator( _map.FirstNode() )
-		End
-		
 	End
 	
 	Struct MapValues
 	
+		Method All:ValueIterator()
+			Return New ValueIterator( _map.FirstNode() )
+		End
+		
+		Private
+		
 		Field _map:Map
 		
 		Method New( map:Map )
 			_map=map
 		End
 		
-		Method Iterator:ValueIterator()
-			Return New ValueIterator( _map.FirstNode() )
-		End
-		
 	End
 	
-	Method Iterator:MapIterator()
-		Return New MapIterator( FirstNode() )
+	#rem monkeydoc Creates a new empty map.
+	#end
+	Method New()
+	End
+	
+	#rem monkeydoc Gets a node iterator.
+	
+	#end
+	
+	Method All:Iterator()
+		Return New Iterator( FirstNode() )
 	End
 	
+	#rem monkeydoc Gets a view of the map's keys.
+	
+	The returned value can be used with an Eachin loop to iterate over the map's keys.
+	
+	@return A MapKeys object.
+
+	#end
 	Property Keys:MapKeys()
 		Return New MapKeys( Self )
 	End
+
+	#rem monkeydoc Gets a view of the map's values.
+	
+	The returned value can be used with an Eachin loop to iterate over the map's values.
 	
+	@return A MapValues object.
+	
+	#end	
 	Property Values:MapValues()
 		Return New MapValues( Self )
 	End
 	
+	#rem monkeydoc Removes all keys from the map.
+	#end
 	Method Clear()
 		_root=Null
 	End
 	
+	#rem monkeydoc Gets the number of keys in the map.
+	
+	@return The number of keys in the map.
+	
+	#end
 	Method Count:Int()
 		If Not _root Return 0
 		Return _root.Count( 0 )
 	End
 
+	#rem monkeydoc Checks if the map is empty.
+	
+	@return True if the map is empty.
+	
+	#end
 	Property Empty:Bool()
 		Return _root=Null
 	End
 
+	#rem monkeydoc Checks if the map contains a given key.
+	
+	@param key The key to check for.
+	
+	@return True if the map contains the key.
+	
+	#end
 	Method Contains:Bool( key:K )
 		Return FindNode( key )<>Null
 	End
 	
+	#rem monkeydoc Sets the value associated with a key in the map.
+	
+	If the map does not contain `key`, a new key/value node is added and true is returned.
+	
+	If the map already contains `key`, its associated value is updated and false is returned.
+	
+	This operator functions identically to Set.
+	
+	@param key The key.
+	
+	@param value The value.
+	
+	@return True if a new node was added to the map.
+	
+	#end
+	Operator[]=( key:K,value:V )
+		Set( key,value )
+	End
+
+	#rem monkeydoc Gets the value associated with a key in the map.
+	
+	@param key The key.
+	
+	@return The value associated with `key`, or null if `key` is not in the map.
+	
+	#end
 	Operator[]:V( key:K )
 		Local node:=FindNode( key )
 		If Not node Return Null
 		Return node._value
 	End
 	
-	Operator[]=( key:K,value:V )
-		Set( key,value )
-	End
-
+	#rem monkeydoc Sets the value associated with a key in the map.
+	
+	If the map does not contain `key`, a new key/value node is added to the map and true is returned.
+	
+	If the map already contains `key`, its associated value is updated and false is returned.
+	
+	@param key The key.
+	
+	@param value The value.
+	
+	@return True if a new node was added to the map, false if an existing node was updated.
+	
+	#end
 	Method Set:Bool( key:K,value:V )
 		If Not _root
 			_root=New Node( key,value,Node.Color.Red,Null )
@@ -242,6 +345,19 @@ Class Map<K,V>
 		Return True
 	End
 	
+	#rem monkeydoc Adds a new key/value pair to a map.
+	
+	If the map does not contain `key', a new key/value node is created and true is returned.
+	
+	If the map already contains `key`, nothing happens and false is returned.
+	
+	@param key The key.
+	
+	@param value The value.
+	
+	@return True if a new node was added to the map, false if the map was not modified.
+	
+	#end
 	Method Add:Bool( key:K,value:V )
 		If Not _root
 			_root=New Node( key,value,Node.Color.Red,Null )
@@ -271,6 +387,19 @@ Class Map<K,V>
 		Return True
 	End
 	
+	#rem monkeydoc Updates the value associated with a key in the map.
+
+	If the map does not contain `key', nothing happens and false is returned.
+	
+	If the map already contains `key`, its associated value is updated and true is returned.
+	
+	@param key The key.
+	
+	@param value The value.
+	
+	@return True if the value associated with `key` was updated, false if the map was not modified.
+	
+	#end
 	Method Update:Bool( key:K,value:V )
 		Local node:=FindNode( key )
 		If Not node Return False
@@ -278,12 +407,26 @@ Class Map<K,V>
 		Return True
 	End
 	
+	#rem monkeydoc Gets the value associated with a key in the map.
+	
+	@param key The key.
+	
+	@return The value associated with the key, or null if the key is not in the map.
+	
+	#end
 	Method Get:V( key:K )
 		Local node:=FindNode( key )
 		If node Return node._value
 		Return Null
 	End
 	
+	#rem monkeydoc Removes a key from the map.
+	
+	@param key The key to remove.
+	
+	@return True if the key was removed, or false if the key is not in the map.
+	
+	#end
 	Method Remove:Bool( key:K )
 		Local node:=FindNode( key )
 		If Not node Return False
@@ -291,6 +434,8 @@ Class Map<K,V>
 		Return True
 	End
 	
+	Private
+	
 	Method FirstNode:Node()
 		If Not _root Return Null
 
@@ -367,8 +512,6 @@ Class Map<K,V>
 		Endif
 	End
 	
-	Private
-
 	Field _root:Node
 	
 	Method RotateLeft( node:Node )

+ 99 - 74
modules/std/stack.monkey2

@@ -88,9 +88,10 @@ Class Stack<T> Implements IContainer<T>
 		Return _length=0
 	End
 
-	#rem monkeydoc Gets an iterator.
+	#rem monkeydoc Gets an iterator to all values in the stack.
+
+	@return A stack iterator.
 	
-	@return An iterator
 	#end
 	Method All:Iterator()
 		Return New Iterator( Self,0 )
@@ -166,7 +167,7 @@ Class Stack<T> Implements IContainer<T>
 	
 	The capacity of a stack is the number of values it can contain before memory needs to be reallocated to store more values.
 	
-	If a stack's length equals its capacity, then the next Push or Insert operation will need to allocate more memory to 'grow' the stack.
+	If a stack's length equals its capacity, then the next Add, Insert or Push operation will need to allocate more memory to 'grow' the stack.
 	
 	You don't normally need to worry about stack capacity, but it can be useful to use [[Reserve]] to preallocate stack storage if you know in advance
 	how many values a stack is likely to contain, in order to prevent the overhead of excessive memory allocation.
@@ -221,8 +222,8 @@ Class Stack<T> Implements IContainer<T>
 	#end
 	Method Erase( index1:Int,index2:Int )
 		DebugAssert( index1>=0 And index1<=_length And index2>=0 And index2<=_length And index1<=index2 )
-		If index1=_length Return
 		
+		If index1=_length Return
 		_data.CopyTo( _data,index2,index1,_length-index2 )
 		Resize( _length-index2+index1 )
 	End
@@ -248,47 +249,6 @@ Class Stack<T> Implements IContainer<T>
 		_seq+=1
 	End
 	
-	#rem monkeydoc Gets the top element of the stack
-	
-	In debug builds, a runtime error will occur if the stack is empty.
-	
-	@return The top element of the stack.
-	
-	#end
-	Property Top:T()
-		DebugAssert( _length,"Stack is empty" )
-		Return _data[_length-1]
-	End
-	
-	#rem monkeydoc Pops the top element off the stack and returns it.
-	
-	In debug builds, a runtime error will occur if the stack is empty.
-	
-	@return The top element of the stack before it was popped.
-	#end
-	Method Pop:T()
-		DebugAssert( _length,"Stack is empty" )
-		
-		_length-=1
-		_seq+=1
-		Local value:=_data[_length]
-		_data[_length]=Null
-		Return value
-	End
-	
-	#rem monkeydoc Pushes a value on the stack.
-	
-	@param value The value to push.
-	
-	#end
-	Method Push( value:T )
-		Reserve( _length+1 )
-		_data[_length]=value
-		_length+=1
-		_seq+=1
-	End
-	
-	
 	#rem monkeydoc Gets the value of a stack element.
 	
 	In debug builds, a runtime error will occur if `index` is less than 0, or greather than or equal to the length of the stack.
@@ -298,6 +258,7 @@ Class Stack<T> Implements IContainer<T>
 	#end
 	Method Get:T( index:Int )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
+		
 		Return _data[index]
 	End
 	
@@ -312,6 +273,7 @@ Class Stack<T> Implements IContainer<T>
 	#end
 	Method Set( index:Int,value:T )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
+		
 		_data[index]=value
 	End
 	
@@ -324,6 +286,7 @@ Class Stack<T> Implements IContainer<T>
 	#end
 	Operator []:T( index:Int )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
+		
 		Return _data[index]
 	End
 	
@@ -338,18 +301,22 @@ Class Stack<T> Implements IContainer<T>
 	#end
 	Operator []=( index:Int,value:T )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
+		
 		_data[index]=value
 	End
 	
 	#rem monkeydoc Adds a value to the end of the stack.
 	
-	This method behaves identically to Push.
+	This method behaves identically to Push( value:T ).
 	
 	@param value The value to add.
 	
 	#end
 	Method Add( value:T )
-		Push( value )
+		Reserve( _length+1 )
+		_data[_length]=value
+		_length+=1
+		_seq+=1
 	End
 	
 	#rem monkeydoc Adds the values in an array to the end of the stack.
@@ -374,7 +341,7 @@ Class Stack<T> Implements IContainer<T>
 		Next
 	End
 
-	'KILLME!
+	'TODO: KILLME! DON'T USE THIS!
 	Method Append<C>( values:C ) Where C Implements IContainer<T>
 		For Local value:=Eachin values
 			Add( value )
@@ -392,7 +359,7 @@ Class Stack<T> Implements IContainer<T>
 	@return The index of the value in the stack, or -1 if the value was not found.
 	
 	#end
-	Method Find:Int( value:T,start:Int=0 )
+	Method FindIndex:Int( value:T,start:Int=0 )
 		DebugAssert( start>=0 And start<=_length )
 		
 		Local i:=start
@@ -414,7 +381,7 @@ Class Stack<T> Implements IContainer<T>
 	@return The index of the value in the stack, or -1 if the value was not found.
 	
 	#end
-	Method FindLast:Int( value:T,start:Int=0 )
+	Method FindLastIndex:Int( value:T,start:Int=0 )
 		DebugAssert( start>=0 And start<=_length )
 		
 		Local i:=_length
@@ -427,13 +394,13 @@ Class Stack<T> Implements IContainer<T>
 	
 	#rem monkeydoc Checks if the stack contains a value.
 	
-	@param value The value to check.
+	@param value The value to check for.
 	
 	@return True if the stack contains the value, else false.
 	
 	#end
 	Method Contains:Bool( value:T )
-		Return Find( value )<>-1
+		Return FindIndex( value )<>-1
 	End
 	
 	#rem monkeydoc Finds and removes the first matching value from the stack.
@@ -442,10 +409,14 @@ Class Stack<T> Implements IContainer<T>
 	
 	@param value The value to remove.
 	
+	@return True if the value was removed.
+	
 	#end
-	Method Remove( value:T,start:Int=0 )
-		Local i:=Find( value,start )
-		If i<>-1 Erase( i )
+	Method Remove:Bool( value:T,start:Int=0 )
+		Local i:=FindIndex( value,start )
+		If i=-1 Return False
+		Erase( i )
+		Return True
 	End
 	
 	#rem monkeydoc Finds and removes the last matching value from the stack.
@@ -454,25 +425,35 @@ Class Stack<T> Implements IContainer<T>
 	
 	@param value The value to remove.
 	
+	@return True if the value was removed.
+	
 	#end
-	Method RemoveLast( value:T,start:Int=0 )
-		Local i:=FindLast( value,start )
-		If i<>-1 Erase( i )
+	Method RemoveLast:Bool( value:T,start:Int=0 )
+		Local i:=FindLastIndex( value,start )
+		If i=-1 Return False
+		Erase( i )
+		Return True
 	End
 	
 	#rem monkeydoc Finds and removes each matching value from the stack.
 	
 	@param value The value to remove.
 	
+	@return The number of values removed.
+	
 	#end	
-	Method RemoveEach( value:T )
-		Local put:=0
+	Method RemoveEach:Int( value:T )
+		Local put:=0,n:=0
 		For Local get:=0 Until _length
-			If _data[get]=value Continue
+			If _data[get]=value 
+				n+=1
+				Continue
+			Endif
 			_data[put]=_data[get]
 			put+=1
 		Next
 		Resize( put )
+		Return n
 	End
 	
 	#rem monkeydoc Returns a range of elements from the stack
@@ -510,15 +491,13 @@ Class Stack<T> Implements IContainer<T>
 	Method Slice:Stack( index1:Int,index2:Int )
 
 		If index1<0
-			index1+=_length
-			If index1<0 index1=0
+			index1=Max( index1+_length,0 )
 		Else If index1>_length
 			index1=_length
 		Endif
 		
 		If index2<0
-			index2+=_length
-			If index2<index1 index2=index1
+			index2=Max( index2+_length,index1 )
 		Else If index2>_length
 			index2=_length
 		Else If index2<index1
@@ -580,32 +559,32 @@ Class Stack<T> Implements IContainer<T>
 	@param compareFunc The function used to compare values.
 
 	#end	
-	Method Sort( lo:Int,hi:Int,cmp:Int( x:T,y:T ) )
+	Method Sort( lo:Int,hi:Int,compareFunc:Int( x:T,y:T ) )
 	
 		If hi<=lo Return
 		
 		If lo+1=hi
-			If cmp( _data[hi],_data[lo] )<0 Swap( hi,lo )
+			If compareFunc( _data[hi],_data[lo] )<0 Swap( hi,lo )
 			Return
 		Endif
 		
 		Local i:=(lo+hi)/2
 		
-		If cmp( _data[i],_data[lo] )<0 Swap( i,lo )
+		If compareFunc( _data[i],_data[lo] )<0 Swap( i,lo )
 
-		If cmp( _data[hi],_data[i] )<0
+		If compareFunc( _data[hi],_data[i] )<0
 			Swap( hi,i )
-			If cmp( _data[i],_data[lo] )<0 Swap( i,lo )
+			If compareFunc( _data[i],_data[lo] )<0 Swap( i,lo )
 		Endif
 		
 		Local x:=lo+1
 		Local y:=hi-1
 		Repeat
 			Local p:=_data[i]
-			While cmp( _data[x],p )<0
+			While compareFunc( _data[x],p )<0
 				x+=1
 			Wend
-			While cmp( p,_data[y] )<0
+			While compareFunc( p,_data[y] )<0
 				y-=1
 			Wend
 			If x>y Exit
@@ -617,9 +596,55 @@ Class Stack<T> Implements IContainer<T>
 			y-=1
 		Until x>y
 
-		Sort( lo,y,cmp )
-		Sort( x,hi,cmp )
+		Sort( lo,y,compareFunc )
+		Sort( x,hi,compareFunc )
+	End
+	
+	'***** Stack style extensions *****
+	
+	#rem monkeydoc Gets the top element of the stack
+	
+	In debug builds, a runtime error will occur if the stack is empty.
+	
+	@return The top element of the stack.
+	
+	#end
+	Property Top:T()
+		DebugAssert( _length,"Stack is empty" )
+		
+		Return _data[_length-1]
+	End
+	
+	#rem monkeydoc Pops the top element off the stack and returns it.
+	
+	In debug builds, a runtime error will occur if the stack is empty.
+	
+	@return The top element of the stack before it was popped.
+	#end
+	Method Pop:T()
+		DebugAssert( _length,"Stack is empty" )
+		
+		_length-=1
+		_seq+=1
+		Local value:=_data[_length]
+		_data[_length]=Null
+		Return value
+	End
+	
+	#rem monkeydoc Pushes a value on the stack.
+
+	This method behaves identically to Add( value:T ).
+	
+	@param value The value to push.
+	
+	#end
+	Method Push( value:T )
+		Add( value )
 	End
+
+'	Method Join:String( separator:String ) Where T=String
+'		Return separator.Join( ToArray() )
+'	End
 	
 End
 

+ 2 - 0
modules/std/std.monkey2

@@ -33,6 +33,8 @@ Namespace std
 #Import "geom.monkey2"
 '#Import "json.monkey2"
 
+#Import "time.monkey2"
+
 Function Main()
 
 	Stream.OpenFuncs["file"]=Lambda:Stream( proto:String,path:String,mode:String )

+ 118 - 0
modules/std/time.monkey2

@@ -0,0 +1,118 @@
+
+Namespace std.time
+
+#rem monkeydoc DateTime class.
+#end
+Class Time
+
+	#rem monkeydoc Seconds (0-61)
+	
+	May include 'leap' seconds.
+	
+	#end
+	Property Seconds:Int()
+		Return _tm.tm_sec
+	End
+	
+	#rem monkeydoc Minutes (0-59)
+	#end
+	Property Minutes:Int()
+		Return _tm.tm_min
+	End
+	
+	#rem monkeydoc Hours since midnight (0-23)
+	#end
+	Property Hours:Int()
+		Return _tm.tm_hour
+	End
+	
+	#rem monkeydoc Day of the month (1-31)
+	#end
+	Property Day:Int()
+		Return _tm.tm_mday
+	End
+	
+	#rem monkeydoc Week day since Sunday (0-6)
+	#end
+	Property WeekDay:Int()
+		Return _tm.tm_wday
+	End
+	
+	#rem monkeydoc Days since January 1 (0-365)
+	#end
+	Property YearDay:Int()
+		Return _tm.tm_yday
+	End
+	
+	#rem monkeydoc Month since January (0-11)
+	#end
+	Property Month:Int()
+		Return _tm.tm_mon
+	End
+	
+	#rem monkeydoc Year
+	#end
+	Property Year:Int()
+		Return _tm.tm_year+1900
+	End
+	
+	#rem monkeydoc True if daylight savings is in effect.
+	#end
+	Property DaylightSavings:Bool()
+		Return _tm.tm_isdst
+	End
+	
+	#rem monkeydoc Converts time to a string.
+	
+	The string format is: WeekDay Day Month Year Hours:Minutes:Seconds
+	
+	#end
+	Method ToString:String()
+		Return _days[ WeekDay ]+" "+Day+" "+_months[ Month ]+" "+Year+" "+ Hours+":"+Minutes+":"+Seconds
+	End
+
+	#rem monkeydoc Overloaded compare operator.
+	
+	Time x is 'less than' time y if time x represents a time 'earlier' than time y.
+	
+	#end	
+	Operator<=>:Int( time:Time )
+		Return libc.difftime( _timer,time._timer )<=>0
+	End
+	
+	#rem monkeydoc Gets current time.
+	#end
+	Function Now:Time()
+		Local timer:=libc.time( Null )
+		Local tm:=libc.localtime( Varptr timer )
+		Return New Time( timer,tm )
+	End
+
+	Private
+	
+	Const _days:=New String[]( "Sun","Mon","Tue","Wed","Thu","Fri","Sat" )
+	Const _months:=New String[]( "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" )
+	
+	Field _timer:libc.time_t	
+	Field _tm:libc.tm_t
+	
+	Method New( timer:libc.time_t,tm:libc.tm_t Ptr )
+		_timer=timer
+		_tm=tm[0]
+	End
+	
+End
+
+#rem monkeydoc Gets the number of seconds since the app started.
+#end
+Function Seconds:Double()
+	Return Double(clock())/Double(CLOCKS_PER_SEC)
+End
+
+#rem monkeydoc Gets the number of milliseconds since the app started.
+#end
+Function Millisecs:Long()
+	'Note:CLOCKS_PER_SECOND=1000000 on macos/linux, 1000 on windows...
+	If CLOCKS_PER_SEC>=1000 Return clock()/(CLOCKS_PER_SEC/1000)
+	Return clock()*(1000/CLOCKS_PER_SEC)	'is that right?!?
+End

+ 3 - 0
src/common.sh

@@ -3,6 +3,7 @@ mx2cc=""
 mx2cc_old=""
 mx2cc_v001=""
 mx2cc_v002=""
+mx2cc_v003=""
 mserver=""
 
 if [ "$OSTYPE" = "linux-gnu" ]
@@ -11,6 +12,7 @@ then
 	mx2cc_old="../devtools/mx2v001/bin/mx2cc_linux"
 	mx2cc_v001="mx2new/mx2cc.buildv001/desktop_release_linux/mx2cc"
 	mx2cc_v002="mx2new/mx2cc.buildv002/desktop_release_linux/mx2cc"
+	mx2cc_v003="mx2new/mx2cc.buildv003/desktop_release_linux/mx2cc"
 	mserver="../devtools/MonkeyXFree86c/bin/mserver_linux"
 	chmod +x $mx2cc_old
 	chmod +x $mserver
@@ -19,6 +21,7 @@ else
 	mx2cc_old="../devtools/mx2v001/bin/mx2cc_macos"
 	mx2cc_v001="mx2new/mx2cc.buildv001/desktop_release_macos/mx2cc.app/Contents/MacOS/mx2cc"
 	mx2cc_v002="mx2new/mx2cc.buildv002/desktop_release_macos/mx2cc.app/Contents/MacOS/mx2cc"
+	mx2cc_v003="mx2new/mx2cc.buildv003/desktop_release_macos/mx2cc.app/Contents/MacOS/mx2cc"
 #	chmod +x $mx2cc_old
 #	chmod +x $mserver
 fi

+ 86 - 155
src/mx2new/class.monkey2

@@ -150,7 +150,9 @@ Class ClassType Extends Type
 					Local type:=iface.Semant( scope )
 					Local ifaceType:=Cast<ClassType>( type )
 					
-					If Not ifaceType Or ifaceType.cdecl.kind<>"interface" Throw New SemantEx( "Type '"+type.ToString()+"' is not a valid interface type" )
+					If Not ifaceType Or (ifaceType.cdecl.kind<>"interface" And ifaceType.cdecl.kind<>"protocol" ) Throw New SemantEx( "Type '"+type.ToString()+"' is not a valid interface type" )
+					
+					If cdecl.kind="interface" And ifaceType.cdecl.kind="protocol" Throw New SemantEx( "Interfaces cannot extends protocols" )
 					
 					If ifaceType.state=SNODE_SEMANTING Throw New SemantEx( "Cyclic inheritance error",cdecl )
 					
@@ -163,6 +165,7 @@ Class ClassType Extends Type
 					For Local iface:=Eachin ifaceType.allIfaces
 						
 						If Not allifaces.Contains( iface ) allifaces.Push( iface )
+
 					Next
 					
 				Catch ex:SemantEx
@@ -177,17 +180,23 @@ Class ClassType Extends Type
 		Endif
 		
 		Local builder:=Builder.instance
-		builder.semantMembers.AddLast( Self )
-	
-		If Not scope.IsGeneric And Not cdecl.IsExtern
 		
-			transFile.classes.Push( Self )
+		If scope.IsGeneric Or cdecl.IsExtern
+		
+			builder.semantMembers.AddLast( Self )
 			
+		Else
+		
 			If IsGenInstance
+				SemantMembers()
 				Local module:=builder.semantingModule 
 				module.genInstances.Push( Self )
+			Else
+				builder.semantMembers.AddLast( Self )
 			Endif
-
+			
+			transFile.classes.Push( Self )
+			
 		Endif
 		
 		Return Self
@@ -195,12 +204,12 @@ Class ClassType Extends Type
 	
 	Method SemantMembers()
 	
-'		Print "SemantMembers "+ToString()
+'		Print "Semanting members: "+ToString()
 	
 		If membersSemanted Or membersSemanting Return
 		membersSemanting=True
 		
-		'enum/semant all funcs
+		'Semant funcs
 		'
 		Local flists:=New Stack<FuncList>
 
@@ -218,195 +227,110 @@ Class ClassType Extends Type
 			flists.Push( flist )
 			
 			For Local func:=Eachin flist.funcs
-				If func.fdecl.IsAbstract Or func.fdecl.IsIfaceMember abstractMethods.Push( func )
-			Next
-		Next
-		
-		'validate operator methods
-		'
-		For Local flist:=Eachin flists
-				
-			For Local func:=Eachin flist.funcs
-				If func.fdecl.kind<>"method" Or Not func.fdecl.IsOperator Continue
-				
-				Try
+			
+				If func.fdecl.IsIfaceMember abstractMethods.Push( func )
 				
-					Local op:=func.fdecl.ident
-					Local opname:="Operator '"+op+"'"
-					
-					Select op
-					Case "=","<>","<",">","<=",">="
-						If func.ftype.retType<>Type.BoolType Throw New SemantEx( opname+" must return Bool" )
-						If func.ftype.argTypes.Length<>1 Or Not func.ftype.argTypes[0].Equals( Self ) Throw New SemantEx( opname+" must have 1 parameter of type '"+ToString()+"'" )
-					Case "<=>"
-						If func.ftype.retType<>Type.IntType Throw New SemantEx( opname+" must return Int" )
-						If func.ftype.argTypes.Length<>1 Or Not func.ftype.argTypes[0].Equals( Self ) Throw New SemantEx( opname+" must have 1 parameter of type '"+ToString()+"'" )
-					End
-
-				Catch ex:SemantEx
-
-				End
-					
 			Next
-
+			
 		Next
 		
-		'validate class/struct overrides
-		'
-		If cdecl.kind="class" Or cdecl.kind="struct" And Not scope.IsGeneric
-		
-			For Local flist:=Eachin flists
-					
-				For Local func:=Eachin flist.funcs
-					If func.fdecl.kind<>"method" Continue
-					
-					Try
-					
-						If func.fdecl.IsOperator
-							Local op:=func.fdecl.ident
-							Select op
-							Case "=","<>","<",">","<=",">="
-								If func.ftype.retType<>Type.BoolType Throw New SemantEx( "Comparison operator '"+op+"' must return Bool" )
-								If func.ftype.argTypes.Length<>1 Throw New SemantEx( "Comparison operator '"+op+"' must have 1 parameter" )
-								If Not func.ftype.argTypes[0].Equals( Self ) Throw New SemantEx( "Comparison operator '"+op+"' parameter must be of type '"+ToString()+"'" )
-							Case "<=>"
-								If func.ftype.retType<>Type.IntType Throw New SemantEx( "Comparison operator '"+op+"' must return Int" )
-								If func.ftype.argTypes.Length<>1 Throw New SemantEx( "Comparison operator '"+op+"' must have 1 parameter" )
-								If Not func.ftype.argTypes[0].Equals( Self ) Throw New SemantEx( "Comparison operator '"+op+"' parameter must be of type '"+ToString()+"'" )
-							End
-						Endif
-					
-						If IsVirtual And (func.fdecl.IsVirtual Or func.fdecl.IsOverride)
-							Throw New SemantEx( "Virtual class methods cannot be declared 'Virtual' or 'Override'",func.fdecl )
-						Endif
-						
-						Local func2:=FindSuperFunc( flist.ident,func.ftype.argTypes )
-						
-						If func2
-						
-							If Not IsVirtual And Not func.fdecl.IsOverride
-								Throw New SemantEx( "Method '"+func.ToString()+"' overrides a superclass method but is not declared 'Override'",func.fdecl )
-							Endif
-	
-							If func2.fdecl.IsFinal
-								Throw New SemantEx( "Method '"+func.ToString()+"' overrides a final superclass method",func.fdecl )
-							Endif
-							
-							If Not IsVirtual And Not func2.fdecl.IsVirtual And Not func2.fdecl.IsOverride And Not func2.fdecl.IsAbstract
-								 Throw New SemantEx( "Method '"+func.ToString()+"' overrides a non-virtual superclass method",func.fdecl )
-							Endif
-								
-							If Not func.ftype.retType.Equals( func2.ftype.retType ) 
-								Throw New SemantEx( "Method '"+func.ToString()+"' overrides a superclass method but has a different return type" )
-							Endif
-	
-						Else
-						
-							If func.fdecl.IsOverride
-								Throw New SemantEx( "Method '"+func.ToString()+"' is declared 'Override' but does not override any superclass method",func.fdecl )
-							Endif
-							
-						Endif
-						
-					Catch ex:SemantEx
-
-					End
-						
-				Next
-				
-			Next
+		If (cdecl.kind="class" Or cdecl.kind="struct") And Not scope.IsGeneric
 		
-			'enum unimplemented superclass abstract methods
+			'Enum unimplemented superclass abstract methods
 			'
 			If superType
 			
 				For Local func:=Eachin superType.abstractMethods
 				
-					Local flist:=Cast<FuncList>( scope.nodes[func.fdecl.ident] )
-					If flist
-						Local func2:=flist.FindFunc( func.ftype.argTypes )
-						If func2
-							If Not func.ftype.retType.Equals( func2.ftype.retType )
-								Try
-									Local t:="superclass method"
-									If func.fdecl.IsIfaceMember t="interface method"
-									Throw New SemantEx( "Method '"+func2.ToString()+"' overrides "+t+" '"+func.ToString()+"' but has a different return type",func2.fdecl )
-								Catch ex:SemantEx
-								End
+					Try
+						Local flist:=Cast<FuncList>( scope.nodes[func.fdecl.ident] )
+						If flist
+							Local func2:=flist.FindFunc( func.ftype.argTypes )
+							If func2
+								If func2.ftype.retType.ExtendsType( func.ftype.retType ) Continue
+								Throw New SemantEx( "Overriding method '"+func2.ToString()+"' has incompatible return type",func2.fdecl )
 							Endif
-							Continue
 						Endif
-					Endif
+						
+						abstractMethods.Push( func )
+						
+					Catch ex:SemantEx
+					End
 					
-					abstractMethods.Push( func )
 				Next
+
 			Endif
 			
-			'enum unimplemented interface methods
+			'Enum unimplemented interface methods
 			'
 			For Local iface:=Eachin allIfaces
-			
-				If superType And superType.DistanceToType( iface )>=0 Continue
-			
+				
+				If superType And superType.ExtendsType( iface ) Continue
+				
 				For Local func:=Eachin iface.abstractMethods
 				
-					Local flist:=Cast<FuncList>( scope.nodes[func.fdecl.ident] )
-					If flist
-						Local func2:=flist.FindFunc( func.ftype.argTypes )
-						If func2
-							If Not func.ftype.retType.Equals( func2.ftype.retType )
-								Try
-									Local t:="superclass method"
-									If func.fdecl.IsIfaceMember t="interface method"
-									Throw New SemantEx( "Method '"+func2.ToString()+"' overrides "+t+" '"+func.ToString()+"' but has a different return type",func2.fdecl )
-								Catch ex:SemantEx
-								End
+'					Print "abstractMethod="+func.ToString()
+
+					Try
+					
+						Local flist:=Cast<FuncList>( scope.nodes[func.fdecl.ident] )
+						If flist
+							Local func2:=flist.FindFunc( func.ftype.argTypes )
+							If func2
+								If func2.ftype.retType.ExtendsType( func.ftype.retType ) Continue
+								Throw New SemantEx( "Overriding method '"+func2.ToString()+"' has incompatible return type",func2.fdecl )
 							Endif
+						Endif
+						
+						If func.fdecl.IsDefault
+							scope.Insert( func.fdecl.ident,func )
 							Continue
 						Endif
-					Endif
+						
+						abstractMethods.Push( func )
 					
-					abstractMethods.Push( func )
+					Catch ex:SemantEx
+					End
+
 				Next
 			
 			Next
+			
+			If superType
+			
+				For Local flist:=Eachin flists
+					
+					Local flist2:=Cast<FuncList>( superType.scope.GetNode( flist.ident ) )
+					If Not flist2 Continue
+						
+					For Local func2:=Eachin flist2.funcs
+						If Not flist.FindFunc( func2.ftype.argTypes ) flist.PushFunc( func2 )
+					Next
+	
+				Next
+			
+			Endif
 		
 		Endif
 		
 		Self.abstractMethods=abstractMethods.ToArray()
-	
-		'add superclass overloads
-		'
-		If (cdecl.kind="class" Or cdecl.kind="struct") And superType
-		
-			For Local flist:=Eachin flists
-				
-				Local flist2:=Cast<FuncList>( superType.scope.GetNode( flist.ident ) )
-				If Not flist2 Continue
-					
-				For Local func2:=Eachin flist2.funcs
-					If Not flist.FindFunc( func2.ftype.argTypes ) flist.PushFunc( func2 )
-				Next
-
-			Next
-
-		Endif
 		
+		'Finished semanting funcs
+		'
 		membersSemanting=False
 		membersSemanted=True
 
-		'semant vars - should probably do this in another phase...
+		'Semant vars - should probably do this in another phase?
 		'		
 		For Local it:=Eachin scope.nodes
 		
 			Try
-
 				If Not Cast<FuncList>( it.Value ) it.Value.Semant()
-			
 			Catch ex:SemantEx
 			End
 			
 		Next
+	
 	End
 	
 	Method FindSuperNode:SNode( ident:String )
@@ -490,6 +414,13 @@ Class ClassType Extends Type
 		Return inst
 	End
 	
+	Method ExtendsType:Bool( type:Type ) Override
+	
+		Local t:=DistanceToType( type )
+		
+		Return t>=0 And t<MAX_DISTANCE
+	End
+	
 	Method DistanceToType:Int( type:Type ) Override
 	
 		If type=Self Return 0
@@ -516,7 +447,7 @@ Class ClassType Extends Type
 		
 			If stype.Equals( ctype ) Return dist
 			
-			If ctype.cdecl.kind="interface" 
+			If ctype.cdecl.kind="interface" Or ctype.cdecl.kind="protocol"
 				For Local iface:=Eachin stype.allIfaces
 					If iface.Equals( ctype ) Return dist
 				Next
@@ -692,7 +623,7 @@ Class ClassScope Extends Scope
 		Next
 		If args args="_1"+args+"E"
 		
-		Return "T"+outer.TypeId+"_"+ctype.cdecl.ident+args+"E"
+		Return "T"+outer.TypeId+"_"+ctype.cdecl.ident.Replace( "_","_0" )+args+"_2"
 	End
 	
 	Property IsGeneric:Bool() Override

+ 6 - 0
src/mx2new/decl.monkey2

@@ -20,6 +20,8 @@ Const DECL_IFACEMEMBER:=2048
 
 Const DECL_EXTENSION:=4096
 
+Const DECL_DEFAULT:=8192
+
 Class Decl Extends PNode
 
 	Field kind:String
@@ -83,6 +85,10 @@ Class Decl Extends PNode
 		Return (flags & DECL_EXTENSION)<>0
 	End
 	
+	Property IsDefault:Bool()
+		Return (flags & DECL_DEFAULT)<>0
+	End
+	
 	Method ToString:String() Override
 		Return kind.Capitalize()+" "+idscope+ident
 	End

+ 100 - 4
src/mx2new/expr.monkey2

@@ -11,7 +11,17 @@ Class Expr Extends PNode
 		Throw New SemantEx( "OnSemant TODO!" )
 		Return Null
 	End
-
+	
+	Method OnSemantType:Type( scope:Scope ) Virtual
+		Throw New SemantEx( "Invalid type expression" )
+		Return Null
+	End
+	
+	Method OnSemantWhere:Bool( scope:Scope ) Virtual
+		Throw New SemantEx( "Invalid 'Where' expression" )
+		Return False
+	End
+	
 	Method Semant:Value( scope:Scope )
 	
 		Try
@@ -57,7 +67,6 @@ Class Expr Extends PNode
 		Return Null
 	End
 	
-	
 	Method TrySemantRValue:Value( scope:Scope,type:Type=Null )
 	
 		Try
@@ -70,6 +79,44 @@ Class Expr Extends PNode
 		Return Null
 	End
 	
+	Method SemantType:Type( scope:Scope )
+
+		Try
+			semanting.Push( Self )
+
+			Local type:=OnSemantType( scope )
+			
+			semanting.Pop()
+			Return type
+		
+		Catch ex:SemantEx
+		
+			semanting.Pop()
+			Throw ex
+		End
+		
+		Return Null
+	End
+
+	Method SemantWhere:Bool( scope:Scope )
+
+		Try
+			semanting.Push( Self )
+			
+			Local twhere:=OnSemantWhere( scope )
+			
+			semanting.Pop()
+			Return twhere
+		
+		Catch ex:SemantEx
+		
+			semanting.Pop()
+			Throw ex
+		End
+		
+		Return False
+	End
+
 End
 
 Class ValueExpr Extends Expr
@@ -108,6 +155,14 @@ Class IdentExpr Extends Expr
 		
 		Return value
 	End
+	
+	Method OnSemantType:Type( scope:Scope ) Override
+	
+		Local type:=scope.FindType( ident )
+		If Not type Throw New SemantEx( "Type '"+ident+"' not found" )
+		
+		Return type
+	End
 
 End
 
@@ -137,6 +192,16 @@ Class MemberExpr Extends Expr
 		Return tvalue
 	End
 	
+	Method OnSemantType:Type( scope:Scope ) Override
+	
+		Local type:=expr.SemantType( scope )
+		
+		Local type2:=type.FindType( ident )
+		If Not type2 Throw New SemantEx( "Identifier '"+ident+"' not found in type '"+type.Name+"'" )
+		
+		Return type2
+	End
+
 End
 
 Class InvokeExpr Extends Expr
@@ -223,6 +288,9 @@ Class NewObjectExpr Extends Expr
 		Local ctype:=Cast<ClassType>( type )
 		If Not ctype Throw New SemantEx( "Type '"+type.ToString()+"' is not a class" )
 		
+		'hmmm...
+		'ctype.SemantMembers()
+		
 		If ctype.IsGeneric Throw New SemantEx( "Class '"+ctype.ToString()+"' is generic" )
 		
 		If ctype.IsAbstract
@@ -348,7 +416,7 @@ Class ExtendsExpr Extends Expr
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local ctype:=Cast<ClassType>( Self.type.Semant( scope ) )
-		If Not ctype Or (ctype.cdecl.kind<>"class" And ctype.cdecl.kind<>"interface") Throw New SemantEx( "Type must be a class or interface '"+type.ToString()+"'" )
+		If Not ctype Or (ctype.cdecl.kind<>"class" And ctype.cdecl.kind<>"interface" And ctype.cdecl.kind<>"protocol" ) Throw New SemantEx( "Type must be a class or interface '"+type.ToString()+"'" )
 		
 		Local value:=Self.expr.SemantRValue( scope )
 
@@ -368,6 +436,16 @@ Class ExtendsExpr Extends Expr
 		
 		Return cvalue.UpCast( Type.BoolType )
 	End
+	
+	Method OnSemantWhere:Bool( scope:Scope ) Override
+	
+		Local ctype:=Cast<ClassType>( Self.type.Semant( scope ) )
+		If Not ctype Or (ctype.cdecl.kind<>"class" And ctype.cdecl.kind<>"interface" And ctype.cdecl.kind<>"protocol" ) Throw New SemantEx( "Type must be a class or interface '"+type.ToString()+"'" )
+		
+		Local type:=Self.expr.SemantType( scope )
+
+		Return type.ExtendsType( ctype )
+	End
 
 End
 
@@ -389,8 +467,14 @@ Class CastExpr Extends Expr
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local type:=Self.type.Semant( scope )
+		
+		Local value:=Self.expr.Semant( scope )
+		
+		If value.type.DistanceToType( type )>=0 Return value.UpCast( type )
+		
+		value=value.ToRValue()
 
-		Local value:=Self.expr.SemantRValue( scope )
+'		Local value:=Self.expr.SemantRValue( scope )
 		
 		If Not value.type.CanCastToType( type ) 
 			Throw New SemantEx( "Value of type '"+value.type.ToString()+"' cannot be cast to type '"+type.ToString()+"'" )
@@ -713,6 +797,18 @@ Class BinaryopExpr Extends Expr
 		Return EvalBinaryop( type,op,lhs.UpCast( lhsType ),rhs.UpCast( rhsType ) )
 	End
 	
+	Method OnSemantWhere:Bool( scope:Scope ) Override
+	
+		If op<>"=" And op<>"<>" Throw New SemantEx( "Types can only be compared for equality" )
+		
+		Local lhs:=Self.lhs.SemantType( scope )
+		Local rhs:=Self.rhs.SemantType( scope )
+		
+		If op="=" Return lhs.Equals( rhs )
+		
+		Return Not lhs.Equals( rhs )
+	End
+	
 End
 
 Class IfThenElseExpr Extends Expr

+ 108 - 38
src/mx2new/func.monkey2

@@ -76,22 +76,19 @@ Class FuncValue Extends Value
 	End
 	
 	Property Name:String()
-		Local name:=scope.Name
-		If name name+="."+fdecl.ident Else name=fdecl.ident
-		Local kind:=fdecl.kind.Capitalize()
-		If fdecl.IsOperator kind="Operator"
-'		Return kind+" "+name+":"+ftype.Name
-		Return name+":"+ftype.Name
+		Local name:=scope.Name+"."+fdecl.ident,ps:=""
+		For Local p:=Eachin params
+			ps+=","+p.Name
+		Next
+		Return name+":"+ftype.retType.Name+"("+ps.Slice( 1 )+")"
 	End
 	
 	Property IsGeneric:Bool()
 		If Not ftype SemantError( "FuncValue.IsGeneric()" )
-		
 		Return ftype.IsGeneric
 	End
 	
 	Property IsGenInstance:Bool()
-	
 		Return instanceOf
 	End
 	
@@ -113,29 +110,101 @@ Class FuncValue Extends Value
 	End
 	
 	Method ToString:String() Override
-'		Return fdecl.ident
 		Local str:=fdecl.ident
 		If types str+="<"+Join( types )+">"
 		Return str+":"+ftype.retType.ToString()+"("+Join( ftype.argTypes )+")"
 	End
 	
 	Method OnSemant:SNode() Override
-
-		'create top func block
-		block=New Block( Self )
-		
-		'insert type args
-		For Local i:=0 Until fdecl.genArgs.Length
-			block.Insert( fdecl.genArgs[i],types[i] )
-		Next
 	
-		'TODO: Generic ctors
-		If IsCtor And types Throw New SemantEx( "Constructors cannot be generic" )
+		'Create top level func block
+		'
+		block=New FuncBlock( Self )
+		
+		'Checks for generic funcs
+		'
+		If types
+			If fdecl.IsAbstract Or fdecl.IsVirtual Or fdecl.IsOverride Throw New SemantEx( "Virtual methods cannot be generic" )
+			If IsCtor Throw New SemantEx( "Constructors cannot be generic" )	'TODO
+		Endif
 
-		'semant func type
+		'Semant func type
+		'
 		type=fdecl.type.Semant( block )
 		ftype=Cast<FuncType>( type )
 		
+		'That's it for generics
+		'
+		If block.IsGeneric 
+			
+			Return Self
+		Endif
+		
+		'Sanity checks!
+		'
+		If fdecl.kind="method" And fdecl.ident<>"new"
+		
+			Local cscope:=Cast<ClassScope>( scope )
+			Local ctype:=cscope.ctype
+			Local cdecl:=ctype.cdecl
+			
+			If fdecl.IsOperator
+				Local op:=fdecl.ident
+				Select op
+				Case "=","<>","<",">","<=",">="
+					If ftype.retType<>Type.BoolType Throw New SemantEx( "Comparison operator '"+op+"' must return Bool" )
+					If ftype.argTypes.Length<>1 Throw New SemantEx( "Comparison operator '"+op+"' must have 1 parameter" )
+					If Not ftype.argTypes[0].Equals( ctype ) Throw New SemantEx( "Comparison operator '"+op+"' parameter must be of type '"+ctype.ToString()+"'" )
+				Case "<=>"
+					If ftype.retType<>Type.IntType Throw New SemantEx( "Comparison operator '"+op+"' must return Int" )
+					If ftype.argTypes.Length<>1 Throw New SemantEx( "Comparison operator '"+op+"' must have 1 parameter" )
+					If Not ftype.argTypes[0].Equals( ctype ) Throw New SemantEx( "Comparison operator '"+op+"' parameter must be of type '"+ctype.ToString()+"'" )
+				End
+			Endif
+			
+			If ctype.IsVirtual And (fdecl.IsVirtual Or fdecl.IsOverride)
+				Throw New SemantEx( "Virtual class methods cannot be declared 'Virtual' or 'Override'" )
+			Endif
+			
+			Local func2:=ctype.FindSuperFunc( fdecl.ident,ftype.argTypes )
+			
+			If func2
+			
+				If Not ctype.IsVirtual And Not fdecl.IsOverride
+					Throw New SemantEx( "Method '"+ToString()+"' overrides a superclass method but is not declared 'Override'" )
+				Endif
+
+				If func2.fdecl.IsFinal
+					Throw New SemantEx( "Method '"+ToString()+"' overrides a final method" )
+				Endif
+				
+				If Not ctype.IsVirtual And Not func2.fdecl.IsVirtual And Not func2.fdecl.IsOverride And Not func2.fdecl.IsAbstract
+					 Throw New SemantEx( "Method '"+ToString()+"' overrides a non-virtual superclass method" )
+				Endif
+					
+				If Not ftype.retType.ExtendsType( func2.ftype.retType ) 
+					Throw New SemantEx( "Method '"+ToString()+"' overrides a method with incompatible return type" )
+				Endif
+
+			Else
+			
+				If fdecl.IsOverride
+					Throw New SemantEx( "Method '"+ToString()+"' is declared 'Override' but does not override any method" )
+				Endif
+				
+			Endif
+		Endif
+
+		'Check 'where' if present...
+		'		
+		If fdecl.whereExpr
+			Local t:=fdecl.whereExpr.SemantWhere( block )
+'			Print "Semanted where for "+Name+" -> "+Int(t)
+			If Not t Return Null
+		Endif
+		
+		'Good to go
+		'
 		If fdecl.kind="lambda"
 			semanted=Self
 			SemantStmts()
@@ -143,8 +212,8 @@ Class FuncValue Extends Value
 			Local builder:=Builder.instance
 			builder.semantStmts.Push( Self )
 		Endif
-		
 		Return Self
+		
 	End
 	
 	Method ToValue:Value( instance:Value ) Override
@@ -159,7 +228,10 @@ Class FuncValue Extends Value
 		
 			If Not instance Throw New SemantEx( "Method '"+ToString()+"' cannot be accessed without an instance" )
 			
-			If instance.type.DistanceToType( Cast<ClassScope>( scope ).ctype )<0 Throw New SemantEx( "Method '"+ToString()+"' cannot be accessed from instance of a different class" )
+			If Not instance.type.ExtendsType( Cast<ClassScope>( scope ).ctype )
+'			If instance.type.DistanceToType( Cast<ClassScope>( scope ).ctype )<0 
+				Throw New SemantEx( "Method '"+ToString()+"' cannot be accessed from instance of a different class" )
+			Endif
 			
 			value=New MemberFuncValue( instance,Self )
 		Endif
@@ -248,7 +320,7 @@ Class FuncValue Extends Value
 	
 	Method SemantStmts()
 	
-		If block.IsGeneric Return
+		If block.IsGeneric SemantError( "FuncValue.SemantStmts()" )
 	
 		Try
 		
@@ -258,7 +330,7 @@ Class FuncValue Extends Value
 		
 		End
 		
-		If Not fdecl.IsAbstract And Not fdecl.IsIfaceMember
+		If Not fdecl.IsAbstract
 			
 			Local reachable:=block.Semant( fdecl.stmts )
 			
@@ -292,23 +364,19 @@ Class FuncValue Extends Value
 	Method TryGenInstance:FuncValue( types:Type[] )
 	
 '		If AnyTypeGeneric( types ) Print "TryGenInstance:"+fdecl.ident+"<"+Join( types )+">"
-	
-		If Not IsGeneric Return Null
-		
+
 		If types.Length<>Self.types.Length Return Null
 		
 		If Not instances instances=New Stack<FuncValue>
 	
 		For Local inst:=Eachin instances
-			If TypesEqual( inst.types,types ) Return inst
+			If TypesEqual( inst.types,types ) Return Cast<FuncValue>( inst.Semant() )
 		Next
 		
 		Local inst:=New FuncValue( fdecl,scope,types,Self )
 		instances.Push( inst )
 		
-		inst.Semant()
-		
-		Return inst
+		Return Cast<FuncValue>( inst.Semant() )
 	End
 	
 	Method FixArgs:Value[]( args:Value[] )
@@ -515,8 +583,10 @@ Class FuncList Extends SNode
 	
 	Method FindFunc:FuncValue( argTypes:Type[] )
 	
+		If AnyTypeGeneric( argTypes ) SemantError( "FuncList.FindFunc()" )
+	
 		For Local func:=Eachin funcs
-			If TypesEqual( func.ftype.argTypes,argTypes ) Return func
+			If Not func.IsGeneric And TypesEqual( func.ftype.argTypes,argTypes ) Return func
 		Next
 		
 		Return Null
@@ -532,12 +602,14 @@ Class FuncList Extends SNode
 		For Local tfunc:=Eachin tfuncs
 		
 			Try
-		
+
 				Local func:=Cast<FuncValue>( tfunc.Semant() )
 				If Not func Continue
-			
-				Local func2:=FindFunc( func.ftype.argTypes )
-				If func2 Throw New SemantEx( "Duplicate declaration '"+func.ToString()+"'",tfunc.pnode )
+				
+				If Not func.IsGeneric
+					Local func2:=FindFunc( func.ftype.argTypes )
+					If func2 Throw New SemantEx( "Duplicate declaration '"+func.ToString()+"'",tfunc.pnode )
+				Endif
 				
 				funcs.Push( func )
 
@@ -559,8 +631,6 @@ Class FuncList Extends SNode
 	
 		If Not instance0 instance0=New FuncListType( Self )
 		
-'		If funcs.Length=1 And Not funcs[0].IsGeneric Return funcs[0].ToValue( instance )
-		
 		Return New FuncListValue( instance0,instance )
 	End
 	

+ 1 - 1
src/mx2new/module.monkey2

@@ -33,7 +33,7 @@ Class Module
 		
 		ident=MungPath( name )
 		baseDir=ExtractDir( srcPath )
-		buildDir=baseDir+name+".buildv002/"
+		buildDir=baseDir+name+".buildv"+MX2_BUILDV+"/"
 		outputDir=buildDir+builder.profileName+"/"
 		cacheDir=buildDir+"build_cache/"+builder.profileName+"/"
 		

+ 4 - 0
src/mx2new/mx2.monkey2

@@ -40,3 +40,7 @@ Using std.chartype
 Using std.filesystem
 Using lib.c
 'Using libc
+
+Global MX2CC_VERSION:="002"
+
+Global MX2_BUILDV:="000"

+ 10 - 3
src/mx2new/mx2cc.monkey2

@@ -14,9 +14,9 @@ Using libc
 
 Global StartDir:String
 
-'Const TestArgs:="mx2cc makemods -clean -verbose -config=debug"
+'Const TestArgs:="mx2cc makemods -verbose -clean -config=release"
 
-Const TestArgs:="mx2cc makeapp -clean -verbose -target=desktop -config=debug src/mx2new/test.monkey2"
+Const TestArgs:="mx2cc makeapp -verbose -target=desktop -config=debug src/mx2new/test.monkey2"
 
 'Const TestArgs:="mx2cc makeapp -verbose -target=desktop -config=release src/mx2new/mx2cc.monkey2"
 
@@ -24,7 +24,7 @@ Const TestArgs:="mx2cc makeapp -clean -verbose -target=desktop -config=debug src
 
 Function Main()
 
-	Print "MX2CC V0.002"
+	Print "MX2CC V0."+MX2CC_VERSION
 
 	StartDir=CurrentDir()
 
@@ -33,6 +33,7 @@ Function Main()
 	Local env:="bin/env_"+HostOS+".txt"
 	
 	While Not IsRootDir( CurrentDir() ) And FileType( env )<>FILETYPE_FILE
+	
 		ChangeDir( ExtractDir( CurrentDir() ) )
 	Wend
 	
@@ -40,6 +41,10 @@ Function Main()
 	
 	LoadEnv( env )
 	
+	MX2_BUILDV=GetEnv( "MX2_BUILDV" )
+	
+	Print "MX2_BUILDV="+MX2_BUILDV
+	
 	Local args:=AppArgs()
 	
 	If args.Length<2
@@ -201,6 +206,8 @@ End
 
 Function ParseOpts:String[]( opts:BuildOpts,args:String[] )
 
+	opts.verbose=Int( GetEnv( "MX2_VERBOSE" ) )
+
 	For Local i:=0 Until args.Length
 	
 		Local arg:=args[i]

+ 18 - 6
src/mx2new/overload.monkey2

@@ -10,6 +10,14 @@ Function IsCandidate:Bool( func:FuncValue,ret:Type,args:Type[],infered:Type[] )
 	Local argTypes:=ftype.argTypes
 	
 	If args.Length>argTypes.Length Return False
+	
+	If ret
+		If retType.IsGeneric
+			If Not retType.InferType( ret,infered ) Return False
+'		Else
+'			If Not ret.Equals( retType ) Return False
+		Endif
+	Endif
 
 	If ret And retType.IsGeneric And Not retType.InferType( ret,infered ) Return False
 	
@@ -49,6 +57,9 @@ Function IsCandidate:Bool( func:FuncValue,ret:Type,args:Type[],infered:Type[] )
 		If Not infered[i] Or infered[i]=Type.BadType Return False
 	Next
 	
+	Return True
+	
+	#rem
 	If Not func.fdecl.whereExpr Return True
 	
 	'Check where expr is 'true'
@@ -64,6 +75,7 @@ Function IsCandidate:Bool( func:FuncValue,ret:Type,args:Type[],infered:Type[] )
 	If Not value Or value.type<>Type.BoolType Throw New SemantEx( "'Where' expression does not evaluate to a constant bool value" )
 	
 	Return value.value="true"
+	#end
 End
 
 Function CanInfer:Bool( func:FuncValue,args:Type[] )
@@ -155,10 +167,8 @@ Function Linearize( types:Type[],func:FuncValue,funcs:Stack<FuncValue>,j:Int=0 )
 	Next
 	
 	Local func2:=func.TryGenInstance( types )
-	
-	If Not func2 SemantError( "FucListType.Linearize()" )
-	
-	funcs.Push( func2 )
+
+	If func2 funcs.Push( func2 )
 End
 
 Public
@@ -181,9 +191,11 @@ Function FindOverload:FuncValue( funcs:Stack<FuncValue>,ret:Type,args:Type[] )
 		If IsCandidate( func,ret,args,infered ) Linearize( infered,func,candidates )
 		
 	Next
-	
-'	Print "Args:"+Join( args )
+
+'	Print "Funcs:"+Join( funcs.ToArray() )
 '	Print "Candidates:"+Join( candidates.ToArray() )
+'	Print "Argtypes:"+Join( args )
+'	If ret Print "Return:"+ret.ToString()
 	
 	Local match:FuncValue
 	

+ 19 - 3
src/mx2new/parser.monkey2

@@ -122,6 +122,8 @@ Class Parser
 				decls.Push( ParseClass( flags ) )
 			Case "interface"
 				decls.Push( ParseClass( flags ) )
+			Case "protocol"
+				decls.Push( ParseClass( flags ) )
 			Case "enum"
 				decls.Push( ParseEnum( flags ) )
 			Case "function"
@@ -243,7 +245,9 @@ Class Parser
 	
 		Local mflags:=DECL_PUBLIC | (flags & DECL_EXTERN)
 		
-		If kind="interface" mflags|=DECL_IFACEMEMBER
+		If kind="interface" mflags|=DECL_IFACEMEMBER|DECL_ABSTRACT
+		
+		If kind="protocol" mflags|=DECL_IFACEMEMBER|DECL_ABSTRACT
 		
 		Try
 			ident=ParseIdent()
@@ -253,6 +257,8 @@ Class Parser
 			If CParse( "extends" )
 				If kind="interface"
 					ifaceTypes=ParseTypes()
+				Else If kind="protocol"
+					ifaceTypes=ParseTypes()
 				Else
 					superType=ParseType()
 				Endif
@@ -267,6 +273,8 @@ Class Parser
 			
 				If kind="interface" Error( "Interfaces are implicitly abstract" )
 				
+				If kind="protocol" Error( "Protocols cannot have modifiers" )
+				
 				If CParse( "virtual" )
 					flags|=DECL_VIRTUAL
 				Else If CParse( "abstract" )
@@ -404,7 +412,7 @@ Class Parser
 			Select Toke
 			Case "virtual","abstract","override","final","extension"
 			
-				If flags & DECL_IFACEMEMBER Error( "Interface methods are implictly abstract" )
+				If (flags & DECL_IFACEMEMBER) Error( "Interface methods are implictly abstract" )
 				
 				If CParse( "virtual" )
 					flags|=DECL_VIRTUAL
@@ -426,6 +434,14 @@ Class Parser
 				whereExpr=ParseExpr()
 			Endif
 			
+			If CParse( "default" )
+				If Not (flags & DECL_IFACEMEMBER) Error( "Only interface methods can be declared 'Default'" )
+				flags&=~DECL_ABSTRACT
+				flags|=DECL_DEFAULT
+				If CParse( "virtual" ) flags|=DECL_VIRTUAL
+			Endif
+			
+			
 			If flags & DECL_EXTERN
 				If CParse( "=" ) symbol=ParseString()
 			Endif
@@ -448,7 +464,7 @@ Class Parser
 		decl.whereExpr=whereExpr
 		decl.symbol=symbol
 		
-		If flags & (DECL_EXTERN|DECL_ABSTRACT|DECL_IFACEMEMBER)
+		If (flags & (DECL_EXTERN|DECL_ABSTRACT)) And Not (flags & DECL_DEFAULT)
 			decl.endpos=EndPos
 			Return decl
 		Endif

+ 22 - 0
src/mx2new/scope.monkey2

@@ -383,3 +383,25 @@ Class Block Extends Scope
 	End
 	
 End
+
+Class FuncBlock Extends Block
+
+	Method New( func:FuncValue )
+		Super.New( func )
+	End
+	
+	Method FindType:Type( ident:String ) Override
+	
+		For Local i:=0 Until func.types.Length
+			If ident=func.fdecl.genArgs[i] Return func.types[i]
+		Next
+
+'		If func.ifaceScope
+'			Local type:=func.ifaceScope.FindType( ident )
+'			If type Return type
+'		Endif
+
+		Return Super.FindType( ident )
+	End
+
+End

+ 4 - 3
src/mx2new/stmtexpr.monkey2

@@ -616,6 +616,7 @@ Class ForStmtExpr Extends StmtExpr
 				
 				'iter=container.Iterator()
 				Local iter:=init.FindValue( "All" )
+				If Not iter iter=init.FindValue( "GetIterator" )
 				If Not iter iter=init.FindValue( "Iterator" )
 				
 				If Not iter Throw New SemantEx( "Container of type '"+init.type.ToString()+"' has no 'Iterator' method" )
@@ -666,13 +667,13 @@ Class ForStmtExpr Extends StmtExpr
 	End
 	
 	Method OnSemant:Stmt( block:Block ) Override
-	
+
 		If kind="eachin" Return SemantEachin( block )
-		
+
 		Local iblock:=New Block( block )
 		block=New Block( iblock )
 		block.loop=True
-		
+
 		Local cond:Value
 		Local incr:Stmt
 

+ 60 - 28
src/mx2new/test.monkey2

@@ -1,50 +1,82 @@
 
 Namespace test
 
-#Import "<std.monkey2>"
+#Import "<libc.monkey2>"
 
-Using std
+Class List<T>
 
-Class C
-
-	Method Update() Virtual
+	Method First:T()
+		Return Null
+	End
 	
-		Print "C.Update()!"
-		
-		Assert( False )
+End
+
+Interface I
+
+	Method Render()
+
+	Method Update() Default Virtual
+		Render()
+		Print "Update!"
 	End
 
 End
 
-Function Test()
+Class C Implements I
 
-	Print "Test!"
-	
-	Local c:C
-	
-	c.Update()
+	Method Render()
+	End	
+
+End
+
+Class D Extends C
+
+	Method Update() Override
+	End
 	
-	New C().Update()
+End
+
+Function Test<T>:T( x:T,y:T ) Where T Implements INumeric
+	Return x<y ? x Else y
+End
+
+Function Test<T>:T( x:T,y:T ) Where T=String
+	Return x+y
+End
+
+Function Sizeof<T>:Int()
+	Return libc.sizeof( Cast<T Ptr>( Null )[0] )
+End
+
+Function Read<T>:Int()
+	Return Null
+End
 
+Struct S
+	Field x:Float
+	Field y:Float
 End
 
 Function Main()
 
-	Local p:Int[]
-	
-	Local f:Float
+	Print Sizeof<S>()
 
-	For Local i:=0 Until 10
-		Local t:=String( i*2 )
-		debug.Stop()
-	Next
+	Print Int( String Implements INumeric )
 
-	Print "Hello World!"
-	
-	Local t:=New Int[10]
-	
-	t[9]=0
+	Print Test( 10,20 )
 
-	Test()
+	Print Test( 10.0,20.0 )
 
+	Print Test( "20","10" )
+	
+	#rem
+	Local c:=New C
+	
+	c.Update()
+	
+	Local list:=New List<Int>
+	
+	Local t:=list.First()
+	#end
+	
 End

+ 1 - 2
src/mx2new/translator.monkey2

@@ -436,8 +436,7 @@ Class Translator
 	
 	Method IsValue:Bool( type:Type )
 	
-		Return Cast<PrimType>( type ) Or IsStruct( type ) Or Cast<FuncType>( type )
-
+		Return Cast<PrimType>( type ) Or Cast<FuncType>( type ) Or IsStruct( type )
 	End
 	
 	Method CFuncType:String( type:FuncType )

+ 18 - 3
src/mx2new/translator_cpp.monkey2

@@ -215,6 +215,8 @@ Class Translator_CPP Extends Translator
 	
 	Method EmitClassProto( ctype:ClassType,fdecl:FileDecl,emitted:StringMap<Bool> )
 	
+		If ctype.cdecl.kind="protocol" Return
+		
 		Local insPos:=InsertPos
 		
 		EmitClassProto( ctype )
@@ -269,6 +271,7 @@ Class Translator_CPP Extends Translator
 		
 		If cdecl.kind<>"struct"
 			For Local iface:=Eachin ctype.ifaceTypes
+				If iface.cdecl.kind="protocol" Continue
 				Uses( iface )
 				If xtends xtends+=","
 				xtends+="public virtual "+ClassName( iface )
@@ -402,6 +405,8 @@ Class Translator_CPP Extends Translator
 	
 	Method EmitClassMembers( ctype:ClassType )
 	
+		If ctype.cdecl.kind="protocol" Return
+		
 		Local cdecl:=ctype.cdecl
 		Local cname:=ClassName( ctype )
 	
@@ -662,7 +667,15 @@ Class Translator_CPP Extends Translator
 	
 		BeginGCFrame( func )
 		
-		If debug Emit( "bbDBFrame db_f{~q"+func.Name+"~q,~q"+func.pnode.srcfile.path+"~q};" )
+		If debug 
+		
+			Emit( "bbDBFrame db_f{~q"+func.Name+"~q,~q"+func.pnode.srcfile.path+"~q};" )
+			
+			For Local vvar:=Eachin func.params
+				Emit( "bbDBLocal(~q"+vvar.vdecl.ident+":"+vvar.type.TypeId+"~q,&"+Trans( vvar )+");" )
+			Next
+			
+		Endif
 		
 		EmitStmts( func.block )
 	
@@ -1049,7 +1062,9 @@ Class Translator_CPP Extends Translator
 		
 		If IsValue( type ) Return TransType( type )+"{}"
 		
-		Return "nullptr"
+		Return "(("+TransType( type )+")(0))"
+		
+'		Return "nullptr"
 	End
 
 	Method Trans:String( value:LiteralValue )
@@ -1220,7 +1235,7 @@ Class Translator_CPP Extends Translator
 	End
 	
 	Method Trans:String( value:IfThenElseValue )
-		Return Trans( value.value )+" ? "+Trans( value.thenValue )+" : "+Trans( value.elseValue )
+		Return "("+Trans( value.value )+" ? "+Trans( value.thenValue )+" : "+Trans( value.elseValue )+")"
 	End
 	
 	Method Trans:String( value:PointerValue )

+ 18 - 9
src/mx2new/type.monkey2

@@ -76,6 +76,10 @@ Class Type Extends SNode
 		Return type=Self
 	End
 	
+	Method ExtendsType:Bool( type:Type ) Virtual
+		Return Equals( type )
+	End
+	
 	Method DistanceToType:Int( type:Type ) Virtual
 		If Equals( type ) Return 0
 		Return -1
@@ -137,12 +141,17 @@ Class PrimType Extends Type
 	
 	Method Equals:Bool( type:Type ) Override
 
-		Return type=Self Or type=ctype
+		Return type=Self 
+	End
+	
+	Method ExtendsType:Bool( type:Type ) Override
+	
+		Return type=Self Or ctype.DistanceToType( type )>=0
 	End
 	
 	Method DistanceToType:Int( type:Type ) Override
 	
-		If type=Self Or type=ctype Return 0
+		If type=Self Return 0
 
 		Local ptype:=Cast<PrimType>( type )
 		If ptype
@@ -156,7 +165,7 @@ Class PrimType Extends Type
 			Return MAX_DISTANCE
 		End
 		
-'		Return ctype.DistanceToType( type )+1
+'		If ExtendsType( type ) Return MAX_DISTANCE
 		
 		Return -1
 	End
@@ -352,7 +361,7 @@ Class PointerType Extends Type
 		If Cast<PointerType>( type ) Return True
 		
 		Local ptype:=Cast<PrimType>( type )
-		If ptype And ptype.IsNumeric Return True
+		If ptype And ptype.IsIntegral Return True
 		
 		Return False
 	End
@@ -390,10 +399,10 @@ Class FuncType Extends Type
 	End
 	
 	Property Name:String() Override
-	
+
 		Local args:=""
 		For Local arg:=Eachin argTypes
-			args+=arg.Name
+			args+=","+arg.Name
 		Next
 		
 		Return retType.Name+"("+args.Slice( 1 )+")"
@@ -479,9 +488,9 @@ Class GenArgType Extends Type
 	
 	Method ToString:String() Override
 
-		Local str:=ident
+		Local str:=ident+"?"
 		If types str+="<"+Join( types )+">"
-		Return str+"?"
+		Return str
 	End
 	
 	Property Name:String() Override
@@ -492,7 +501,7 @@ Class GenArgType Extends Type
 		Next
 		If args args="<"+args.Slice( 1 )+">"
 		
-		Return ident+args+"?"
+		Return ident+"?"+args
 	End
 	
 	Property TypeId:String() Override

+ 4 - 0
src/mx2new/var.monkey2

@@ -88,6 +88,10 @@ Class VarValue Extends Value
 		Return Self
 	End
 	
+	Property Name:String()
+		Return vdecl.ident+":"+type.Name
+	End
+	
 	Method ToString:String() Override
 		Return vdecl.ident
 	End

+ 10 - 10
tests/std/filesystem.monkey2

@@ -5,17 +5,17 @@ Using std.filesystemex
 
 Function Main()
 
-	Local cd:=GetCurrentDirectory()
-	Local parent:=GetParentDirectory( cd )
+	Local cd:=CurrentDir()
+	Local parent:=GetParentDir( cd )
 	
 	Print cd
 	Print parent
 	
-	SetCurrentDirectory( parent )
-	Print GetCurrentDirectory()
+	ChangeDir( parent )
+	Print CurrentDir()
 	
-	SetCurrentDirectory( cd )
-	Print GetCurrentDirectory()
+	ChangeDir( cd )
+	Print CurrentDir()
 	
 	Print GetRealPath( "test/one" )				'test/one
 	Print GetRealPath( "test//one" )			'test/one
@@ -23,16 +23,16 @@ Function Main()
 	Print GetRealPath( "test//one///" )			'test/one/
 	Print GetRealPath( "test/one/two/../" )		'test/one/
 	
-	CreateDirectory( "one/two/three" )
+	CreateDir( "one/two/three" )
 	Print Int( GetFileType( "one/two/three" ) )	'2
 	
-	DeleteDirectory( "one/two/three" )
+	DeleteDir( "one/two/three" )
 	Print Int( GetFileType( "one/two/three" ) )	'0
 
-	DeleteDirectory( "one" )
+	DeleteDir( "one" )
 	Print Int( GetFileType( "one" ) )			'2
 
-	DeleteDirectory( "one",True )
+	DeleteDir( "one",True )
 	Print Int( GetFileType( "one" ) )			'0
 
 End

+ 39 - 0
tests/std/time.monkey2

@@ -0,0 +1,39 @@
+
+#Import "<std.monkey2>"
+
+Using std.time
+
+Function Main()
+
+	Print "Seconds() at start="+Seconds()
+
+	Print "CLOCKS_PER_SEC="+libc.CLOCKS_PER_SEC
+	
+	Local start:=Seconds()
+	Print "Waiting 5 seconds..."
+	While Seconds()<start+5
+	Wend
+	Print "Done!"
+
+	Local time:=Time.Now()
+	
+	Print time.Seconds
+	Print time.Minutes
+	Print time.Hours
+	Print time.Day
+	Print time.Month
+	Print time.Year
+	Print "Daylight savings="+(time.DaylightSavings ? "true" Else "false")
+	
+	Print time.ToString()
+
+	start=Seconds()
+	While Seconds()<start+1
+	Wend
+		
+	Local time2:=Time.Now()
+	
+	Print time<=>time2		'-1
+	Print time2<=>time		'1
+	
+End