瀏覽代碼

Cleanups, bugfixes, docs etc.

blitz-research 9 年之前
父節點
當前提交
3065fee7e5

+ 3 - 0
bin/env_linux.txt

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

+ 3 - 0
bin/env_macos.txt

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

+ 3 - 0
bin/env_windows.txt

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

二進制
bin/mx2cc_linux


二進制
bin/mx2cc_macos


二進制
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 *****
 '***** 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 *****
 '***** unistd.h *****
 
 
@@ -67,7 +92,7 @@ Function rmdir:Int( path:CString )
 Enum mode_t
 Enum mode_t
 End
 End
 
 
-Const S_IFMT:mode_t	'$f000
+Const S_IFMT:mode_t		'$f000
 Const S_IFIFO:mode_t	'$1000
 Const S_IFIFO:mode_t	'$1000
 Const S_IFCHR:mode_t	'$2000
 Const S_IFCHR:mode_t	'$2000
 Const S_IFBLK:mode_t	'$3000
 Const S_IFBLK:mode_t	'$3000

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

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

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

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

+ 13 - 9
modules/std/container.monkey2

@@ -5,17 +5,20 @@ Namespace std
 #end
 #end
 Interface IContainer<T>
 Interface IContainer<T>
 
 
-	Property Empty:Bool()
+	'Property Empty:Bool()
 	
 	
 	'Method All:IIterator<T>()
 	'Method All:IIterator<T>()
+
+	'Method Find:IIterator<T>( value:T ) Default...
+
 	
 	
 	'For sequences...
 	'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
 End
 
 
@@ -23,16 +26,17 @@ End
 #end
 #end
 Interface IIterator<T>
 Interface IIterator<T>
 
 
-	Property Valid:Bool()
+	'Property Valid:Bool()
+	
+	'Property Current:T()
 	
 	
-	Property Current:T()
+	'Method Bump()
 	
 	
-	Method Bump()
 	
 	
 	'For sequences...
 	'For sequences...
 	
 	
-	Method Erase()
+	'Method Erase()
 	
 	
-	Method Insert( value:T )
+	'Method Insert( value:T )
 	
 	
 End
 End

+ 2 - 2
modules/std/filesystem.monkey2

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

+ 27 - 29
modules/std/filesystemex.monkey2

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

+ 98 - 17
modules/std/list.monkey2

@@ -87,7 +87,7 @@ Class List<T> Implements IContainer<T>
 	Field _length:Int
 	Field _length:Int
 	Field _seq:Int
 	Field _seq:Int
 	
 	
-	#rem monkeydoc Creates a new empty list
+	#rem monkeydoc Creates a new empty list.
 	#end
 	#end
 	Method New()
 	Method New()
 	End
 	End
@@ -101,6 +101,11 @@ Class List<T> Implements IContainer<T>
 		AddAll( values )
 		AddAll( values )
 	End
 	End
 	
 	
+	#rem monkeydoc Gets an iterator to all values in the list.
+
+	@return A list iterator.
+	
+	#end
 	Method All:Iterator()
 	Method All:Iterator()
 		Return New Iterator( Self,_first )
 		Return New Iterator( Self,_first )
 	End
 	End
@@ -111,7 +116,7 @@ Class List<T> Implements IContainer<T>
 	
 	
 	#end
 	#end
 	Property Empty:Bool()
 	Property Empty:Bool()
-		Return _first=Null
+		Return _length=0
 	End
 	End
 	
 	
 	#rem monkeydoc Gets the number of values in the list.
 	#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.
 	#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.
 	@return The first value in the list.
 	
 	
@@ -151,9 +156,9 @@ Class List<T> Implements IContainer<T>
 		Return _first._value
 		Return _first._value
 	End
 	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.
 	@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.
 	#rem monkeydoc Adds a value to the start of the list.
 	
 	
 	@param value The value to add to the list.
 	@param value The value to add to the list.
+	
+	@return The new node containing the value.
 
 
 	#end
 	#end
 	Method AddFirst( value:T )
 	Method AddFirst( value:T )
@@ -209,15 +216,16 @@ Class List<T> Implements IContainer<T>
 		_seq+=1
 		_seq+=1
 	End
 	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
 	#end
 	Method RemoveFirst:T()
 	Method RemoveFirst:T()
-		DebugAssert( Not Empty )
+		DebugAssert( _length )
+		
 		Local value:=_first._value
 		Local value:=_first._value
 		_first=_first._succ
 		_first=_first._succ
 		If _first _first._pred=Null Else _last=Null
 		If _first _first._pred=Null Else _last=Null
@@ -226,15 +234,16 @@ Class List<T> Implements IContainer<T>
 		Return value
 		Return value
 	End
 	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
 	#end
 	Method RemoveLast:T()
 	Method RemoveLast:T()
-		DebugAssert( Not Empty )
+		DebugAssert( _length )
+		
 		Local value:=_last._value
 		Local value:=_last._value
 		_last=_last._pred
 		_last=_last._pred
 		If _last _last._succ=Null Else _first=Null
 		If _last _last._succ=Null Else _first=Null
@@ -243,20 +252,82 @@ Class List<T> Implements IContainer<T>
 		Return value
 		Return value
 	End
 	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
 	#end
-	Method RemoveEach( value:T )
+	Method FindNode:Node( value:T )
 		Local node:=_first
 		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
 		While node
 			If node._value=value
 			If node._value=value
 				node=Erase( node )
 				node=Erase( node )
+				n+=1
 			Else
 			Else
 				node=node._succ
 				node=node._succ
 			Endif
 			Endif
 		Wend
 		Wend
+		Return n
 	End
 	End
 
 
 	#rem monkeydoc Gets an iterator for the value at a given index in the list.
 	#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
 		Next
 	End
 	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 )
 	Method Erase:Node( node:Node )
 		If Not node Return Null	'OK to erase tail element...
 		If Not node Return Null	'OK to erase tail element...

+ 182 - 39
modules/std/map.monkey2

@@ -1,10 +1,34 @@
 
 
 Namespace std
 Namespace std
 
 
+#rem monkedoc The Map class.
+#end
 Class Map<K,V>
 Class Map<K,V>
 
 
+	#rem monkeydoc The map Node class.
+	#end
 	Class Node
 	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
 		Enum Color
 			Red
 			Red
 			Black
 			Black
@@ -24,14 +48,6 @@ Class Map<K,V>
 			_parent=parent
 			_parent=parent
 		End
 		End
 		
 		
-		Property Key:K()
-			Return _key
-		End
-		
-		Property Value:V()
-			Return _value
-		End
-	
 		Method Count:Int( n:Int )
 		Method Count:Int( n:Int )
 			If _left n=_left.Count( n )
 			If _left n=_left.Count( n )
 			If _right n=_right.Count( n )
 			If _right n=_right.Count( n )
@@ -79,14 +95,8 @@ Class Map<K,V>
 	
 	
 	End
 	End
 	
 	
-	Struct MapIterator
+	Struct Iterator
 	
 	
-		Field _node:Node
-		
-		Method New( node:Node )
-			_node=node
-		End
-		
 		Property Valid:Bool()
 		Property Valid:Bool()
 			Return _node
 			Return _node
 		End
 		End
@@ -99,16 +109,18 @@ Class Map<K,V>
 			_node=_node.NextNode()
 			_node=_node.NextNode()
 		End
 		End
 		
 		
-	End
-	
-	Struct KeyIterator
-	
+		Private
+		
 		Field _node:Node
 		Field _node:Node
 		
 		
 		Method New( node:Node )
 		Method New( node:Node )
 			_node=node
 			_node=node
 		End
 		End
 		
 		
+	End
+	
+	Struct KeyIterator
+	
 		Property Valid:Bool()
 		Property Valid:Bool()
 			Return _node
 			Return _node
 		End
 		End
@@ -121,16 +133,18 @@ Class Map<K,V>
 			_node=_node.NextNode()
 			_node=_node.NextNode()
 		End
 		End
 		
 		
-	End
-	
-	Struct ValueIterator
-	
+		Private
+		
 		Field _node:Node
 		Field _node:Node
 		
 		
 		Method New( node:Node )
 		Method New( node:Node )
 			_node=node
 			_node=node
 		End
 		End
 		
 		
+	End
+	
+	Struct ValueIterator
+	
 		Property Valid:Bool()
 		Property Valid:Bool()
 			Return _node
 			Return _node
 		End
 		End
@@ -143,75 +157,164 @@ Class Map<K,V>
 			_node=_node.NextNode()
 			_node=_node.NextNode()
 		End
 		End
 		
 		
+		Private
+		
+		Field _node:Node
+		
+		Method New( node:Node )
+			_node=node
+		End
+		
 	End
 	End
 	
 	
 	Struct MapKeys
 	Struct MapKeys
 	
 	
+		Method All:KeyIterator()
+			Return New KeyIterator( _map.FirstNode() )
+		End
+		
+		Private
+		
 		Field _map:Map
 		Field _map:Map
 		
 		
 		Method New( map:Map )
 		Method New( map:Map )
 			_map=map
 			_map=map
 		End
 		End
 		
 		
-		Method Iterator:KeyIterator()
-			Return New KeyIterator( _map.FirstNode() )
-		End
-		
 	End
 	End
 	
 	
 	Struct MapValues
 	Struct MapValues
 	
 	
+		Method All:ValueIterator()
+			Return New ValueIterator( _map.FirstNode() )
+		End
+		
+		Private
+		
 		Field _map:Map
 		Field _map:Map
 		
 		
 		Method New( map:Map )
 		Method New( map:Map )
 			_map=map
 			_map=map
 		End
 		End
 		
 		
-		Method Iterator:ValueIterator()
-			Return New ValueIterator( _map.FirstNode() )
-		End
-		
 	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
 	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()
 	Property Keys:MapKeys()
 		Return New MapKeys( Self )
 		Return New MapKeys( Self )
 	End
 	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()
 	Property Values:MapValues()
 		Return New MapValues( Self )
 		Return New MapValues( Self )
 	End
 	End
 	
 	
+	#rem monkeydoc Removes all keys from the map.
+	#end
 	Method Clear()
 	Method Clear()
 		_root=Null
 		_root=Null
 	End
 	End
 	
 	
+	#rem monkeydoc Gets the number of keys in the map.
+	
+	@return The number of keys in the map.
+	
+	#end
 	Method Count:Int()
 	Method Count:Int()
 		If Not _root Return 0
 		If Not _root Return 0
 		Return _root.Count( 0 )
 		Return _root.Count( 0 )
 	End
 	End
 
 
+	#rem monkeydoc Checks if the map is empty.
+	
+	@return True if the map is empty.
+	
+	#end
 	Property Empty:Bool()
 	Property Empty:Bool()
 		Return _root=Null
 		Return _root=Null
 	End
 	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 )
 	Method Contains:Bool( key:K )
 		Return FindNode( key )<>Null
 		Return FindNode( key )<>Null
 	End
 	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 )
 	Operator[]:V( key:K )
 		Local node:=FindNode( key )
 		Local node:=FindNode( key )
 		If Not node Return Null
 		If Not node Return Null
 		Return node._value
 		Return node._value
 	End
 	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 )
 	Method Set:Bool( key:K,value:V )
 		If Not _root
 		If Not _root
 			_root=New Node( key,value,Node.Color.Red,Null )
 			_root=New Node( key,value,Node.Color.Red,Null )
@@ -242,6 +345,19 @@ Class Map<K,V>
 		Return True
 		Return True
 	End
 	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 )
 	Method Add:Bool( key:K,value:V )
 		If Not _root
 		If Not _root
 			_root=New Node( key,value,Node.Color.Red,Null )
 			_root=New Node( key,value,Node.Color.Red,Null )
@@ -271,6 +387,19 @@ Class Map<K,V>
 		Return True
 		Return True
 	End
 	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 )
 	Method Update:Bool( key:K,value:V )
 		Local node:=FindNode( key )
 		Local node:=FindNode( key )
 		If Not node Return False
 		If Not node Return False
@@ -278,12 +407,26 @@ Class Map<K,V>
 		Return True
 		Return True
 	End
 	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 )
 	Method Get:V( key:K )
 		Local node:=FindNode( key )
 		Local node:=FindNode( key )
 		If node Return node._value
 		If node Return node._value
 		Return Null
 		Return Null
 	End
 	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 )
 	Method Remove:Bool( key:K )
 		Local node:=FindNode( key )
 		Local node:=FindNode( key )
 		If Not node Return False
 		If Not node Return False
@@ -291,6 +434,8 @@ Class Map<K,V>
 		Return True
 		Return True
 	End
 	End
 	
 	
+	Private
+	
 	Method FirstNode:Node()
 	Method FirstNode:Node()
 		If Not _root Return Null
 		If Not _root Return Null
 
 
@@ -367,8 +512,6 @@ Class Map<K,V>
 		Endif
 		Endif
 	End
 	End
 	
 	
-	Private
-
 	Field _root:Node
 	Field _root:Node
 	
 	
 	Method RotateLeft( node:Node )
 	Method RotateLeft( node:Node )

+ 99 - 74
modules/std/stack.monkey2

@@ -88,9 +88,10 @@ Class Stack<T> Implements IContainer<T>
 		Return _length=0
 		Return _length=0
 	End
 	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
 	#end
 	Method All:Iterator()
 	Method All:Iterator()
 		Return New Iterator( Self,0 )
 		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.
 	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
 	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.
 	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
 	#end
 	Method Erase( index1:Int,index2:Int )
 	Method Erase( index1:Int,index2:Int )
 		DebugAssert( index1>=0 And index1<=_length And index2>=0 And index2<=_length And index1<=index2 )
 		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 )
 		_data.CopyTo( _data,index2,index1,_length-index2 )
 		Resize( _length-index2+index1 )
 		Resize( _length-index2+index1 )
 	End
 	End
@@ -248,47 +249,6 @@ Class Stack<T> Implements IContainer<T>
 		_seq+=1
 		_seq+=1
 	End
 	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.
 	#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.
 	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
 	#end
 	Method Get:T( index:Int )
 	Method Get:T( index:Int )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
+		
 		Return _data[index]
 		Return _data[index]
 	End
 	End
 	
 	
@@ -312,6 +273,7 @@ Class Stack<T> Implements IContainer<T>
 	#end
 	#end
 	Method Set( index:Int,value:T )
 	Method Set( index:Int,value:T )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
+		
 		_data[index]=value
 		_data[index]=value
 	End
 	End
 	
 	
@@ -324,6 +286,7 @@ Class Stack<T> Implements IContainer<T>
 	#end
 	#end
 	Operator []:T( index:Int )
 	Operator []:T( index:Int )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
+		
 		Return _data[index]
 		Return _data[index]
 	End
 	End
 	
 	
@@ -338,18 +301,22 @@ Class Stack<T> Implements IContainer<T>
 	#end
 	#end
 	Operator []=( index:Int,value:T )
 	Operator []=( index:Int,value:T )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
 		DebugAssert( index>=0 And index<_length,"Stack index out of range" )
+		
 		_data[index]=value
 		_data[index]=value
 	End
 	End
 	
 	
 	#rem monkeydoc Adds a value to the end of the stack.
 	#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.
 	@param value The value to add.
 	
 	
 	#end
 	#end
 	Method Add( value:T )
 	Method Add( value:T )
-		Push( value )
+		Reserve( _length+1 )
+		_data[_length]=value
+		_length+=1
+		_seq+=1
 	End
 	End
 	
 	
 	#rem monkeydoc Adds the values in an array to the end of the stack.
 	#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
 		Next
 	End
 	End
 
 
-	'KILLME!
+	'TODO: KILLME! DON'T USE THIS!
 	Method Append<C>( values:C ) Where C Implements IContainer<T>
 	Method Append<C>( values:C ) Where C Implements IContainer<T>
 		For Local value:=Eachin values
 		For Local value:=Eachin values
 			Add( value )
 			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.
 	@return The index of the value in the stack, or -1 if the value was not found.
 	
 	
 	#end
 	#end
-	Method Find:Int( value:T,start:Int=0 )
+	Method FindIndex:Int( value:T,start:Int=0 )
 		DebugAssert( start>=0 And start<=_length )
 		DebugAssert( start>=0 And start<=_length )
 		
 		
 		Local i:=start
 		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.
 	@return The index of the value in the stack, or -1 if the value was not found.
 	
 	
 	#end
 	#end
-	Method FindLast:Int( value:T,start:Int=0 )
+	Method FindLastIndex:Int( value:T,start:Int=0 )
 		DebugAssert( start>=0 And start<=_length )
 		DebugAssert( start>=0 And start<=_length )
 		
 		
 		Local i:=_length
 		Local i:=_length
@@ -427,13 +394,13 @@ Class Stack<T> Implements IContainer<T>
 	
 	
 	#rem monkeydoc Checks if the stack contains a value.
 	#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.
 	@return True if the stack contains the value, else false.
 	
 	
 	#end
 	#end
 	Method Contains:Bool( value:T )
 	Method Contains:Bool( value:T )
-		Return Find( value )<>-1
+		Return FindIndex( value )<>-1
 	End
 	End
 	
 	
 	#rem monkeydoc Finds and removes the first matching value from the stack.
 	#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.
 	@param value The value to remove.
 	
 	
+	@return True if the value was removed.
+	
 	#end
 	#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
 	End
 	
 	
 	#rem monkeydoc Finds and removes the last matching value from the stack.
 	#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.
 	@param value The value to remove.
 	
 	
+	@return True if the value was removed.
+	
 	#end
 	#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
 	End
 	
 	
 	#rem monkeydoc Finds and removes each matching value from the stack.
 	#rem monkeydoc Finds and removes each matching value from the stack.
 	
 	
 	@param value The value to remove.
 	@param value The value to remove.
 	
 	
+	@return The number of values removed.
+	
 	#end	
 	#end	
-	Method RemoveEach( value:T )
-		Local put:=0
+	Method RemoveEach:Int( value:T )
+		Local put:=0,n:=0
 		For Local get:=0 Until _length
 		For Local get:=0 Until _length
-			If _data[get]=value Continue
+			If _data[get]=value 
+				n+=1
+				Continue
+			Endif
 			_data[put]=_data[get]
 			_data[put]=_data[get]
 			put+=1
 			put+=1
 		Next
 		Next
 		Resize( put )
 		Resize( put )
+		Return n
 	End
 	End
 	
 	
 	#rem monkeydoc Returns a range of elements from the stack
 	#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 )
 	Method Slice:Stack( index1:Int,index2:Int )
 
 
 		If index1<0
 		If index1<0
-			index1+=_length
-			If index1<0 index1=0
+			index1=Max( index1+_length,0 )
 		Else If index1>_length
 		Else If index1>_length
 			index1=_length
 			index1=_length
 		Endif
 		Endif
 		
 		
 		If index2<0
 		If index2<0
-			index2+=_length
-			If index2<index1 index2=index1
+			index2=Max( index2+_length,index1 )
 		Else If index2>_length
 		Else If index2>_length
 			index2=_length
 			index2=_length
 		Else If index2<index1
 		Else If index2<index1
@@ -580,32 +559,32 @@ Class Stack<T> Implements IContainer<T>
 	@param compareFunc The function used to compare values.
 	@param compareFunc The function used to compare values.
 
 
 	#end	
 	#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 hi<=lo Return
 		
 		
 		If lo+1=hi
 		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
 			Return
 		Endif
 		Endif
 		
 		
 		Local i:=(lo+hi)/2
 		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 )
 			Swap( hi,i )
-			If cmp( _data[i],_data[lo] )<0 Swap( i,lo )
+			If compareFunc( _data[i],_data[lo] )<0 Swap( i,lo )
 		Endif
 		Endif
 		
 		
 		Local x:=lo+1
 		Local x:=lo+1
 		Local y:=hi-1
 		Local y:=hi-1
 		Repeat
 		Repeat
 			Local p:=_data[i]
 			Local p:=_data[i]
-			While cmp( _data[x],p )<0
+			While compareFunc( _data[x],p )<0
 				x+=1
 				x+=1
 			Wend
 			Wend
-			While cmp( p,_data[y] )<0
+			While compareFunc( p,_data[y] )<0
 				y-=1
 				y-=1
 			Wend
 			Wend
 			If x>y Exit
 			If x>y Exit
@@ -617,9 +596,55 @@ Class Stack<T> Implements IContainer<T>
 			y-=1
 			y-=1
 		Until x>y
 		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
 	End
+
+'	Method Join:String( separator:String ) Where T=String
+'		Return separator.Join( ToArray() )
+'	End
 	
 	
 End
 End
 
 

+ 2 - 0
modules/std/std.monkey2

@@ -33,6 +33,8 @@ Namespace std
 #Import "geom.monkey2"
 #Import "geom.monkey2"
 '#Import "json.monkey2"
 '#Import "json.monkey2"
 
 
+#Import "time.monkey2"
+
 Function Main()
 Function Main()
 
 
 	Stream.OpenFuncs["file"]=Lambda:Stream( proto:String,path:String,mode:String )
 	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_old=""
 mx2cc_v001=""
 mx2cc_v001=""
 mx2cc_v002=""
 mx2cc_v002=""
+mx2cc_v003=""
 mserver=""
 mserver=""
 
 
 if [ "$OSTYPE" = "linux-gnu" ]
 if [ "$OSTYPE" = "linux-gnu" ]
@@ -11,6 +12,7 @@ then
 	mx2cc_old="../devtools/mx2v001/bin/mx2cc_linux"
 	mx2cc_old="../devtools/mx2v001/bin/mx2cc_linux"
 	mx2cc_v001="mx2new/mx2cc.buildv001/desktop_release_linux/mx2cc"
 	mx2cc_v001="mx2new/mx2cc.buildv001/desktop_release_linux/mx2cc"
 	mx2cc_v002="mx2new/mx2cc.buildv002/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"
 	mserver="../devtools/MonkeyXFree86c/bin/mserver_linux"
 	chmod +x $mx2cc_old
 	chmod +x $mx2cc_old
 	chmod +x $mserver
 	chmod +x $mserver
@@ -19,6 +21,7 @@ else
 	mx2cc_old="../devtools/mx2v001/bin/mx2cc_macos"
 	mx2cc_old="../devtools/mx2v001/bin/mx2cc_macos"
 	mx2cc_v001="mx2new/mx2cc.buildv001/desktop_release_macos/mx2cc.app/Contents/MacOS/mx2cc"
 	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_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 $mx2cc_old
 #	chmod +x $mserver
 #	chmod +x $mserver
 fi
 fi

+ 86 - 155
src/mx2new/class.monkey2

@@ -150,7 +150,9 @@ Class ClassType Extends Type
 					Local type:=iface.Semant( scope )
 					Local type:=iface.Semant( scope )
 					Local ifaceType:=Cast<ClassType>( type )
 					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 )
 					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
 					For Local iface:=Eachin ifaceType.allIfaces
 						
 						
 						If Not allifaces.Contains( iface ) allifaces.Push( iface )
 						If Not allifaces.Contains( iface ) allifaces.Push( iface )
+
 					Next
 					Next
 					
 					
 				Catch ex:SemantEx
 				Catch ex:SemantEx
@@ -177,17 +180,23 @@ Class ClassType Extends Type
 		Endif
 		Endif
 		
 		
 		Local builder:=Builder.instance
 		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
 			If IsGenInstance
+				SemantMembers()
 				Local module:=builder.semantingModule 
 				Local module:=builder.semantingModule 
 				module.genInstances.Push( Self )
 				module.genInstances.Push( Self )
+			Else
+				builder.semantMembers.AddLast( Self )
 			Endif
 			Endif
-
+			
+			transFile.classes.Push( Self )
+			
 		Endif
 		Endif
 		
 		
 		Return Self
 		Return Self
@@ -195,12 +204,12 @@ Class ClassType Extends Type
 	
 	
 	Method SemantMembers()
 	Method SemantMembers()
 	
 	
-'		Print "SemantMembers "+ToString()
+'		Print "Semanting members: "+ToString()
 	
 	
 		If membersSemanted Or membersSemanting Return
 		If membersSemanted Or membersSemanting Return
 		membersSemanting=True
 		membersSemanting=True
 		
 		
-		'enum/semant all funcs
+		'Semant funcs
 		'
 		'
 		Local flists:=New Stack<FuncList>
 		Local flists:=New Stack<FuncList>
 
 
@@ -218,195 +227,110 @@ Class ClassType Extends Type
 			flists.Push( flist )
 			flists.Push( flist )
 			
 			
 			For Local func:=Eachin flist.funcs
 			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
-
+			
 		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
 			If superType
 			
 			
 				For Local func:=Eachin superType.abstractMethods
 				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
 							Endif
-							Continue
 						Endif
 						Endif
-					Endif
+						
+						abstractMethods.Push( func )
+						
+					Catch ex:SemantEx
+					End
 					
 					
-					abstractMethods.Push( func )
 				Next
 				Next
+
 			Endif
 			Endif
 			
 			
-			'enum unimplemented interface methods
+			'Enum unimplemented interface methods
 			'
 			'
 			For Local iface:=Eachin allIfaces
 			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
 				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
+						Endif
+						
+						If func.fdecl.IsDefault
+							scope.Insert( func.fdecl.ident,func )
 							Continue
 							Continue
 						Endif
 						Endif
-					Endif
+						
+						abstractMethods.Push( func )
 					
 					
-					abstractMethods.Push( func )
+					Catch ex:SemantEx
+					End
+
 				Next
 				Next
 			
 			
 			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
 		Endif
 		
 		
 		Self.abstractMethods=abstractMethods.ToArray()
 		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
 		membersSemanting=False
 		membersSemanted=True
 		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
 		For Local it:=Eachin scope.nodes
 		
 		
 			Try
 			Try
-
 				If Not Cast<FuncList>( it.Value ) it.Value.Semant()
 				If Not Cast<FuncList>( it.Value ) it.Value.Semant()
-			
 			Catch ex:SemantEx
 			Catch ex:SemantEx
 			End
 			End
 			
 			
 		Next
 		Next
+	
 	End
 	End
 	
 	
 	Method FindSuperNode:SNode( ident:String )
 	Method FindSuperNode:SNode( ident:String )
@@ -490,6 +414,13 @@ Class ClassType Extends Type
 		Return inst
 		Return inst
 	End
 	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
 	Method DistanceToType:Int( type:Type ) Override
 	
 	
 		If type=Self Return 0
 		If type=Self Return 0
@@ -516,7 +447,7 @@ Class ClassType Extends Type
 		
 		
 			If stype.Equals( ctype ) Return dist
 			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
 				For Local iface:=Eachin stype.allIfaces
 					If iface.Equals( ctype ) Return dist
 					If iface.Equals( ctype ) Return dist
 				Next
 				Next
@@ -692,7 +623,7 @@ Class ClassScope Extends Scope
 		Next
 		Next
 		If args args="_1"+args+"E"
 		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
 	End
 	
 	
 	Property IsGeneric:Bool() Override
 	Property IsGeneric:Bool() Override

+ 6 - 0
src/mx2new/decl.monkey2

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

+ 100 - 4
src/mx2new/expr.monkey2

@@ -11,7 +11,17 @@ Class Expr Extends PNode
 		Throw New SemantEx( "OnSemant TODO!" )
 		Throw New SemantEx( "OnSemant TODO!" )
 		Return Null
 		Return Null
 	End
 	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 )
 	Method Semant:Value( scope:Scope )
 	
 	
 		Try
 		Try
@@ -57,7 +67,6 @@ Class Expr Extends PNode
 		Return Null
 		Return Null
 	End
 	End
 	
 	
-	
 	Method TrySemantRValue:Value( scope:Scope,type:Type=Null )
 	Method TrySemantRValue:Value( scope:Scope,type:Type=Null )
 	
 	
 		Try
 		Try
@@ -70,6 +79,44 @@ Class Expr Extends PNode
 		Return Null
 		Return Null
 	End
 	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
 End
 
 
 Class ValueExpr Extends Expr
 Class ValueExpr Extends Expr
@@ -108,6 +155,14 @@ Class IdentExpr Extends Expr
 		
 		
 		Return value
 		Return value
 	End
 	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
 End
 
 
@@ -137,6 +192,16 @@ Class MemberExpr Extends Expr
 		Return tvalue
 		Return tvalue
 	End
 	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
 End
 
 
 Class InvokeExpr Extends Expr
 Class InvokeExpr Extends Expr
@@ -223,6 +288,9 @@ Class NewObjectExpr Extends Expr
 		Local ctype:=Cast<ClassType>( type )
 		Local ctype:=Cast<ClassType>( type )
 		If Not ctype Throw New SemantEx( "Type '"+type.ToString()+"' is not a class" )
 		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.IsGeneric Throw New SemantEx( "Class '"+ctype.ToString()+"' is generic" )
 		
 		
 		If ctype.IsAbstract
 		If ctype.IsAbstract
@@ -348,7 +416,7 @@ Class ExtendsExpr Extends Expr
 	Method OnSemant:Value( scope:Scope ) Override
 	Method OnSemant:Value( scope:Scope ) Override
 	
 	
 		Local ctype:=Cast<ClassType>( Self.type.Semant( scope ) )
 		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 )
 		Local value:=Self.expr.SemantRValue( scope )
 
 
@@ -368,6 +436,16 @@ Class ExtendsExpr Extends Expr
 		
 		
 		Return cvalue.UpCast( Type.BoolType )
 		Return cvalue.UpCast( Type.BoolType )
 	End
 	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
 End
 
 
@@ -389,8 +467,14 @@ Class CastExpr Extends Expr
 	Method OnSemant:Value( scope:Scope ) Override
 	Method OnSemant:Value( scope:Scope ) Override
 	
 	
 		Local type:=Self.type.Semant( scope )
 		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 ) 
 		If Not value.type.CanCastToType( type ) 
 			Throw New SemantEx( "Value of type '"+value.type.ToString()+"' cannot be cast to type '"+type.ToString()+"'" )
 			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 ) )
 		Return EvalBinaryop( type,op,lhs.UpCast( lhsType ),rhs.UpCast( rhsType ) )
 	End
 	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
 End
 
 
 Class IfThenElseExpr Extends Expr
 Class IfThenElseExpr Extends Expr

+ 108 - 38
src/mx2new/func.monkey2

@@ -76,22 +76,19 @@ Class FuncValue Extends Value
 	End
 	End
 	
 	
 	Property Name:String()
 	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
 	End
 	
 	
 	Property IsGeneric:Bool()
 	Property IsGeneric:Bool()
 		If Not ftype SemantError( "FuncValue.IsGeneric()" )
 		If Not ftype SemantError( "FuncValue.IsGeneric()" )
-		
 		Return ftype.IsGeneric
 		Return ftype.IsGeneric
 	End
 	End
 	
 	
 	Property IsGenInstance:Bool()
 	Property IsGenInstance:Bool()
-	
 		Return instanceOf
 		Return instanceOf
 	End
 	End
 	
 	
@@ -113,29 +110,101 @@ Class FuncValue Extends Value
 	End
 	End
 	
 	
 	Method ToString:String() Override
 	Method ToString:String() Override
-'		Return fdecl.ident
 		Local str:=fdecl.ident
 		Local str:=fdecl.ident
 		If types str+="<"+Join( types )+">"
 		If types str+="<"+Join( types )+">"
 		Return str+":"+ftype.retType.ToString()+"("+Join( ftype.argTypes )+")"
 		Return str+":"+ftype.retType.ToString()+"("+Join( ftype.argTypes )+")"
 	End
 	End
 	
 	
 	Method OnSemant:SNode() Override
 	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 )
 		type=fdecl.type.Semant( block )
 		ftype=Cast<FuncType>( type )
 		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"
 		If fdecl.kind="lambda"
 			semanted=Self
 			semanted=Self
 			SemantStmts()
 			SemantStmts()
@@ -143,8 +212,8 @@ Class FuncValue Extends Value
 			Local builder:=Builder.instance
 			Local builder:=Builder.instance
 			builder.semantStmts.Push( Self )
 			builder.semantStmts.Push( Self )
 		Endif
 		Endif
-		
 		Return Self
 		Return Self
+		
 	End
 	End
 	
 	
 	Method ToValue:Value( instance:Value ) Override
 	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 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 )
 			value=New MemberFuncValue( instance,Self )
 		Endif
 		Endif
@@ -248,7 +320,7 @@ Class FuncValue Extends Value
 	
 	
 	Method SemantStmts()
 	Method SemantStmts()
 	
 	
-		If block.IsGeneric Return
+		If block.IsGeneric SemantError( "FuncValue.SemantStmts()" )
 	
 	
 		Try
 		Try
 		
 		
@@ -258,7 +330,7 @@ Class FuncValue Extends Value
 		
 		
 		End
 		End
 		
 		
-		If Not fdecl.IsAbstract And Not fdecl.IsIfaceMember
+		If Not fdecl.IsAbstract
 			
 			
 			Local reachable:=block.Semant( fdecl.stmts )
 			Local reachable:=block.Semant( fdecl.stmts )
 			
 			
@@ -292,23 +364,19 @@ Class FuncValue Extends Value
 	Method TryGenInstance:FuncValue( types:Type[] )
 	Method TryGenInstance:FuncValue( types:Type[] )
 	
 	
 '		If AnyTypeGeneric( types ) Print "TryGenInstance:"+fdecl.ident+"<"+Join( types )+">"
 '		If AnyTypeGeneric( types ) Print "TryGenInstance:"+fdecl.ident+"<"+Join( types )+">"
-	
-		If Not IsGeneric Return Null
-		
+
 		If types.Length<>Self.types.Length Return Null
 		If types.Length<>Self.types.Length Return Null
 		
 		
 		If Not instances instances=New Stack<FuncValue>
 		If Not instances instances=New Stack<FuncValue>
 	
 	
 		For Local inst:=Eachin instances
 		For Local inst:=Eachin instances
-			If TypesEqual( inst.types,types ) Return inst
+			If TypesEqual( inst.types,types ) Return Cast<FuncValue>( inst.Semant() )
 		Next
 		Next
 		
 		
 		Local inst:=New FuncValue( fdecl,scope,types,Self )
 		Local inst:=New FuncValue( fdecl,scope,types,Self )
 		instances.Push( inst )
 		instances.Push( inst )
 		
 		
-		inst.Semant()
-		
-		Return inst
+		Return Cast<FuncValue>( inst.Semant() )
 	End
 	End
 	
 	
 	Method FixArgs:Value[]( args:Value[] )
 	Method FixArgs:Value[]( args:Value[] )
@@ -515,8 +583,10 @@ Class FuncList Extends SNode
 	
 	
 	Method FindFunc:FuncValue( argTypes:Type[] )
 	Method FindFunc:FuncValue( argTypes:Type[] )
 	
 	
+		If AnyTypeGeneric( argTypes ) SemantError( "FuncList.FindFunc()" )
+	
 		For Local func:=Eachin funcs
 		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
 		Next
 		
 		
 		Return Null
 		Return Null
@@ -532,12 +602,14 @@ Class FuncList Extends SNode
 		For Local tfunc:=Eachin tfuncs
 		For Local tfunc:=Eachin tfuncs
 		
 		
 			Try
 			Try
-		
+
 				Local func:=Cast<FuncValue>( tfunc.Semant() )
 				Local func:=Cast<FuncValue>( tfunc.Semant() )
 				If Not func Continue
 				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 )
 				funcs.Push( func )
 
 
@@ -559,8 +631,6 @@ Class FuncList Extends SNode
 	
 	
 		If Not instance0 instance0=New FuncListType( Self )
 		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 )
 		Return New FuncListValue( instance0,instance )
 	End
 	End
 	
 	

+ 1 - 1
src/mx2new/module.monkey2

@@ -33,7 +33,7 @@ Class Module
 		
 		
 		ident=MungPath( name )
 		ident=MungPath( name )
 		baseDir=ExtractDir( srcPath )
 		baseDir=ExtractDir( srcPath )
-		buildDir=baseDir+name+".buildv002/"
+		buildDir=baseDir+name+".buildv"+MX2_BUILDV+"/"
 		outputDir=buildDir+builder.profileName+"/"
 		outputDir=buildDir+builder.profileName+"/"
 		cacheDir=buildDir+"build_cache/"+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 std.filesystem
 Using lib.c
 Using lib.c
 'Using libc
 '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
 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"
 '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()
 Function Main()
 
 
-	Print "MX2CC V0.002"
+	Print "MX2CC V0."+MX2CC_VERSION
 
 
 	StartDir=CurrentDir()
 	StartDir=CurrentDir()
 
 
@@ -33,6 +33,7 @@ Function Main()
 	Local env:="bin/env_"+HostOS+".txt"
 	Local env:="bin/env_"+HostOS+".txt"
 	
 	
 	While Not IsRootDir( CurrentDir() ) And FileType( env )<>FILETYPE_FILE
 	While Not IsRootDir( CurrentDir() ) And FileType( env )<>FILETYPE_FILE
+	
 		ChangeDir( ExtractDir( CurrentDir() ) )
 		ChangeDir( ExtractDir( CurrentDir() ) )
 	Wend
 	Wend
 	
 	
@@ -40,6 +41,10 @@ Function Main()
 	
 	
 	LoadEnv( env )
 	LoadEnv( env )
 	
 	
+	MX2_BUILDV=GetEnv( "MX2_BUILDV" )
+	
+	Print "MX2_BUILDV="+MX2_BUILDV
+	
 	Local args:=AppArgs()
 	Local args:=AppArgs()
 	
 	
 	If args.Length<2
 	If args.Length<2
@@ -201,6 +206,8 @@ End
 
 
 Function ParseOpts:String[]( opts:BuildOpts,args:String[] )
 Function ParseOpts:String[]( opts:BuildOpts,args:String[] )
 
 
+	opts.verbose=Int( GetEnv( "MX2_VERBOSE" ) )
+
 	For Local i:=0 Until args.Length
 	For Local i:=0 Until args.Length
 	
 	
 		Local arg:=args[i]
 		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
 	Local argTypes:=ftype.argTypes
 	
 	
 	If args.Length>argTypes.Length Return False
 	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
 	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
 		If Not infered[i] Or infered[i]=Type.BadType Return False
 	Next
 	Next
 	
 	
+	Return True
+	
+	#rem
 	If Not func.fdecl.whereExpr Return True
 	If Not func.fdecl.whereExpr Return True
 	
 	
 	'Check where expr is '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" )
 	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"
 	Return value.value="true"
+	#end
 End
 End
 
 
 Function CanInfer:Bool( func:FuncValue,args:Type[] )
 Function CanInfer:Bool( func:FuncValue,args:Type[] )
@@ -155,10 +167,8 @@ Function Linearize( types:Type[],func:FuncValue,funcs:Stack<FuncValue>,j:Int=0 )
 	Next
 	Next
 	
 	
 	Local func2:=func.TryGenInstance( types )
 	Local func2:=func.TryGenInstance( types )
-	
-	If Not func2 SemantError( "FucListType.Linearize()" )
-	
-	funcs.Push( func2 )
+
+	If func2 funcs.Push( func2 )
 End
 End
 
 
 Public
 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 )
 		If IsCandidate( func,ret,args,infered ) Linearize( infered,func,candidates )
 		
 		
 	Next
 	Next
-	
-'	Print "Args:"+Join( args )
+
+'	Print "Funcs:"+Join( funcs.ToArray() )
 '	Print "Candidates:"+Join( candidates.ToArray() )
 '	Print "Candidates:"+Join( candidates.ToArray() )
+'	Print "Argtypes:"+Join( args )
+'	If ret Print "Return:"+ret.ToString()
 	
 	
 	Local match:FuncValue
 	Local match:FuncValue
 	
 	

+ 19 - 3
src/mx2new/parser.monkey2

@@ -122,6 +122,8 @@ Class Parser
 				decls.Push( ParseClass( flags ) )
 				decls.Push( ParseClass( flags ) )
 			Case "interface"
 			Case "interface"
 				decls.Push( ParseClass( flags ) )
 				decls.Push( ParseClass( flags ) )
+			Case "protocol"
+				decls.Push( ParseClass( flags ) )
 			Case "enum"
 			Case "enum"
 				decls.Push( ParseEnum( flags ) )
 				decls.Push( ParseEnum( flags ) )
 			Case "function"
 			Case "function"
@@ -243,7 +245,9 @@ Class Parser
 	
 	
 		Local mflags:=DECL_PUBLIC | (flags & DECL_EXTERN)
 		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
 		Try
 			ident=ParseIdent()
 			ident=ParseIdent()
@@ -253,6 +257,8 @@ Class Parser
 			If CParse( "extends" )
 			If CParse( "extends" )
 				If kind="interface"
 				If kind="interface"
 					ifaceTypes=ParseTypes()
 					ifaceTypes=ParseTypes()
+				Else If kind="protocol"
+					ifaceTypes=ParseTypes()
 				Else
 				Else
 					superType=ParseType()
 					superType=ParseType()
 				Endif
 				Endif
@@ -267,6 +273,8 @@ Class Parser
 			
 			
 				If kind="interface" Error( "Interfaces are implicitly abstract" )
 				If kind="interface" Error( "Interfaces are implicitly abstract" )
 				
 				
+				If kind="protocol" Error( "Protocols cannot have modifiers" )
+				
 				If CParse( "virtual" )
 				If CParse( "virtual" )
 					flags|=DECL_VIRTUAL
 					flags|=DECL_VIRTUAL
 				Else If CParse( "abstract" )
 				Else If CParse( "abstract" )
@@ -404,7 +412,7 @@ Class Parser
 			Select Toke
 			Select Toke
 			Case "virtual","abstract","override","final","extension"
 			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" )
 				If CParse( "virtual" )
 					flags|=DECL_VIRTUAL
 					flags|=DECL_VIRTUAL
@@ -426,6 +434,14 @@ Class Parser
 				whereExpr=ParseExpr()
 				whereExpr=ParseExpr()
 			Endif
 			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 flags & DECL_EXTERN
 				If CParse( "=" ) symbol=ParseString()
 				If CParse( "=" ) symbol=ParseString()
 			Endif
 			Endif
@@ -448,7 +464,7 @@ Class Parser
 		decl.whereExpr=whereExpr
 		decl.whereExpr=whereExpr
 		decl.symbol=symbol
 		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
 			decl.endpos=EndPos
 			Return decl
 			Return decl
 		Endif
 		Endif

+ 22 - 0
src/mx2new/scope.monkey2

@@ -383,3 +383,25 @@ Class Block Extends Scope
 	End
 	End
 	
 	
 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()
 				'iter=container.Iterator()
 				Local iter:=init.FindValue( "All" )
 				Local iter:=init.FindValue( "All" )
+				If Not iter iter=init.FindValue( "GetIterator" )
 				If Not iter iter=init.FindValue( "Iterator" )
 				If Not iter iter=init.FindValue( "Iterator" )
 				
 				
 				If Not iter Throw New SemantEx( "Container of type '"+init.type.ToString()+"' has no 'Iterator' method" )
 				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
 	End
 	
 	
 	Method OnSemant:Stmt( block:Block ) Override
 	Method OnSemant:Stmt( block:Block ) Override
-	
+
 		If kind="eachin" Return SemantEachin( block )
 		If kind="eachin" Return SemantEachin( block )
-		
+
 		Local iblock:=New Block( block )
 		Local iblock:=New Block( block )
 		block=New Block( iblock )
 		block=New Block( iblock )
 		block.loop=True
 		block.loop=True
-		
+
 		Local cond:Value
 		Local cond:Value
 		Local incr:Stmt
 		Local incr:Stmt
 
 

+ 60 - 28
src/mx2new/test.monkey2

@@ -1,50 +1,82 @@
 
 
 Namespace test
 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
 
 
 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
 End
 
 
 Function Main()
 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
 End

+ 1 - 2
src/mx2new/translator.monkey2

@@ -436,8 +436,7 @@ Class Translator
 	
 	
 	Method IsValue:Bool( type:Type )
 	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
 	End
 	
 	
 	Method CFuncType:String( type:FuncType )
 	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> )
 	Method EmitClassProto( ctype:ClassType,fdecl:FileDecl,emitted:StringMap<Bool> )
 	
 	
+		If ctype.cdecl.kind="protocol" Return
+		
 		Local insPos:=InsertPos
 		Local insPos:=InsertPos
 		
 		
 		EmitClassProto( ctype )
 		EmitClassProto( ctype )
@@ -269,6 +271,7 @@ Class Translator_CPP Extends Translator
 		
 		
 		If cdecl.kind<>"struct"
 		If cdecl.kind<>"struct"
 			For Local iface:=Eachin ctype.ifaceTypes
 			For Local iface:=Eachin ctype.ifaceTypes
+				If iface.cdecl.kind="protocol" Continue
 				Uses( iface )
 				Uses( iface )
 				If xtends xtends+=","
 				If xtends xtends+=","
 				xtends+="public virtual "+ClassName( iface )
 				xtends+="public virtual "+ClassName( iface )
@@ -402,6 +405,8 @@ Class Translator_CPP Extends Translator
 	
 	
 	Method EmitClassMembers( ctype:ClassType )
 	Method EmitClassMembers( ctype:ClassType )
 	
 	
+		If ctype.cdecl.kind="protocol" Return
+		
 		Local cdecl:=ctype.cdecl
 		Local cdecl:=ctype.cdecl
 		Local cname:=ClassName( ctype )
 		Local cname:=ClassName( ctype )
 	
 	
@@ -662,7 +667,15 @@ Class Translator_CPP Extends Translator
 	
 	
 		BeginGCFrame( func )
 		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 )
 		EmitStmts( func.block )
 	
 	
@@ -1049,7 +1062,9 @@ Class Translator_CPP Extends Translator
 		
 		
 		If IsValue( type ) Return TransType( type )+"{}"
 		If IsValue( type ) Return TransType( type )+"{}"
 		
 		
-		Return "nullptr"
+		Return "(("+TransType( type )+")(0))"
+		
+'		Return "nullptr"
 	End
 	End
 
 
 	Method Trans:String( value:LiteralValue )
 	Method Trans:String( value:LiteralValue )
@@ -1220,7 +1235,7 @@ Class Translator_CPP Extends Translator
 	End
 	End
 	
 	
 	Method Trans:String( value:IfThenElseValue )
 	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
 	End
 	
 	
 	Method Trans:String( value:PointerValue )
 	Method Trans:String( value:PointerValue )

+ 18 - 9
src/mx2new/type.monkey2

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

+ 4 - 0
src/mx2new/var.monkey2

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

+ 10 - 10
tests/std/filesystem.monkey2

@@ -5,17 +5,17 @@ Using std.filesystemex
 
 
 Function Main()
 Function Main()
 
 
-	Local cd:=GetCurrentDirectory()
-	Local parent:=GetParentDirectory( cd )
+	Local cd:=CurrentDir()
+	Local parent:=GetParentDir( cd )
 	
 	
 	Print cd
 	Print cd
 	Print parent
 	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
 	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///" )			'test/one/
 	Print GetRealPath( "test/one/two/../" )		'test/one/
 	Print GetRealPath( "test/one/two/../" )		'test/one/
 	
 	
-	CreateDirectory( "one/two/three" )
+	CreateDir( "one/two/three" )
 	Print Int( GetFileType( "one/two/three" ) )	'2
 	Print Int( GetFileType( "one/two/three" ) )	'2
 	
 	
-	DeleteDirectory( "one/two/three" )
+	DeleteDir( "one/two/three" )
 	Print Int( GetFileType( "one/two/three" ) )	'0
 	Print Int( GetFileType( "one/two/three" ) )	'0
 
 
-	DeleteDirectory( "one" )
+	DeleteDir( "one" )
 	Print Int( GetFileType( "one" ) )			'2
 	Print Int( GetFileType( "one" ) )			'2
 
 
-	DeleteDirectory( "one",True )
+	DeleteDir( "one",True )
 	Print Int( GetFileType( "one" ) )			'0
 	Print Int( GetFileType( "one" ) )			'0
 
 
 End
 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