浏览代码

Cleaned up mx2cc; removed tyepexprs; added support for To operator; started work on extensions.

Mark Sibly 9 年之前
父节点
当前提交
c88d90fce4

+ 3 - 2
src/mx2cc/alias.monkey2

@@ -4,7 +4,7 @@ Namespace mx2
 Class AliasDecl Extends Decl
 
 	Field genArgs:String[]
-	Field type:TypeExpr
+	Field type:Expr
 	
 	Method ToNode:SNode( scope:Scope ) Override
 	
@@ -14,6 +14,7 @@ Class AliasDecl Extends Decl
 		Next
 		
 		Return New AliasType( Self,scope,types,Null )
+		
 	End
 End
 
@@ -52,7 +53,7 @@ Class AliasType Extends ProxyType
 			Next
 		Endif
 		
-		_alias=adecl.type.Semant( tscope )
+		_alias=adecl.type.SemantType( tscope )
 		
 		flags=_alias.flags
 		

+ 7 - 2
src/mx2cc/balance.monkey2

@@ -31,12 +31,14 @@ End
 
 Function BalancePrimTypes:Type( lhs:PrimType,rhs:PrimType )
 
+	If lhs=Type.StringType Or rhs=Type.StringType Return Type.StringType
+	
+	If lhs=Type.BoolType Or rhs=Type.BoolType Return Type.BoolType
+	
 	If Not lhs Or Not rhs
 		Throw New SemantEx( "Types must be primitive" )
 	Endif
 
-	If lhs=Type.StringType Or rhs=Type.StringType Return Type.StringType
-	
 	Return BalanceNumericTypes( lhs,rhs )
 End
 
@@ -117,6 +119,9 @@ Function BalanceBinaryopTypes:Type( op:String,lhs:Type,rhs:Type,argTypes:Type[]
 		ltype=BalanceTypes( lhs,rhs )
 		rtype=ltype
 		
+	Case "and","or"
+
+		type=Type.BoolType
 	End
 	
 	If Not type Throw New SemantEx( "Invalid operand types for binary operator '"+op+"'" )

+ 156 - 0
src/mx2cc/block.monkey2

@@ -0,0 +1,156 @@
+
+Namespace mx2
+
+Class Block Extends Scope
+
+	Field func:FuncValue
+
+	Field stmts:=New Stack<Stmt>
+	
+	Field reachable:Bool=True
+	
+	Field loop:Bool
+	Field inex:Bool
+	
+	Method New( func:FuncValue )
+		Super.New( func.scope )
+		
+		Self.func=func
+	End
+	
+	Method New( outer:Block )
+		Super.New( outer )
+		
+		func=outer.func
+		loop=outer.loop
+		inex=outer.inex
+	End
+	
+'	Property IsGeneric:Bool() Override
+
+'		If func.IsGeneric Return True
+
+'		Return Super.IsGeneric
+'	End
+
+	Method FindValue:Value( ident:String ) Override
+
+		Local node:=FindNode( ident )
+		If Not node Return Null
+		
+		Local vvar:=Cast<VarValue>( node )
+		If vvar
+		
+			Select vvar.vdecl.kind
+			Case "local","param","capture"
+			
+				Local vfunc:=Cast<Block>( vvar.scope ).func
+				
+				If vfunc<>func
+				
+					If func.fdecl.kind<>"lambda" Return Null
+					
+					'capture vvar...
+					'
+					'find all funcs (lambdas) up to vvar func
+					'
+					Local tfunc:=func,funcs:=New Stack<FuncValue>
+
+					While tfunc<>vfunc
+						funcs.Push( tfunc )
+						tfunc=Cast<Block>( tfunc.block.outer ).func
+					Wend
+					
+					While Not funcs.Empty
+					
+						Local tfunc:=funcs.Pop()
+						
+						'FXIME: this pollutes outer func scope with captured var name.
+						'
+						vvar=New VarValue( "capture",vvar.vdecl.ident,vvar,tfunc.block )
+						tfunc.block.Insert( vvar.vdecl.ident,vvar )
+						tfunc.captures.Push( vvar )
+					
+					Wend
+					
+					node=vvar
+					
+				Endif
+			End
+			
+		Endif
+		
+		Return node.ToValue( func.selfValue )
+	End
+	
+	Method Emit( stmt:Stmt )
+	
+		If reachable stmts.Push( stmt )
+	End
+	
+	Method Semant( stmts:StmtExpr[] )
+	
+		Scope.semanting.Push( Self )
+	
+		For Local expr:=Eachin stmts
+			Try
+
+				Local stmt:=expr.Semant( Self )
+				If stmt Emit( stmt )
+				
+			Catch ex:SemantEx
+			End
+		Next
+		
+		Scope.semanting.Pop()
+	End
+	
+	Method AllocLocal:VarValue( init:Value )
+
+		Local ident:=""+func.nextLocalId
+		func.nextLocalId+=1
+
+		Local varValue:=New VarValue( "local",ident,init,Self )
+		
+		stmts.Push( New VarDeclStmt( Null,varValue ) )
+
+		Return varValue
+	End
+
+	Method AllocLocal:VarValue( ident:String,init:Value )
+
+		Local varValue:=New VarValue( "local",ident,init,Self )
+		
+		stmts.Push( New VarDeclStmt( Null,varValue ) )
+
+		Insert( ident,varValue )
+
+		Return varValue
+	End
+	
+End
+
+Class FuncBlock Extends Block
+
+	Method New( func:FuncValue )
+
+		Super.New( func )
+	End
+	
+	Property IsGeneric:Bool() Override
+	
+		If func.IsGeneric Return True
+		
+		Return Super.IsGeneric
+	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
+
+		Return Super.FindType( ident )
+	End
+
+End

+ 35 - 13
src/mx2cc/builder.monkey2

@@ -1,13 +1,13 @@
 
 Namespace mx2
 
+Global Builder:BuilderInstance
+
 Class BuildOpts
 
 	Field mainSource:String
 	
-	Field productType:String
-	
-	Field appType:String
+	Field productType:String	'"app" or "module"
 	
 	Field target:String
 	
@@ -15,6 +15,14 @@ Class BuildOpts
 	
 	Field clean:Bool
 	
+	Field product:String
+
+	Field assets:String
+
+	Field dlls:String
+
+	Field appType:String
+	
 	Field verbose:Int
 	
 	Field fast:Bool
@@ -23,10 +31,8 @@ Class BuildOpts
 	
 End
 
-Class Builder
+Class BuilderInstance
 
-	Global instance:Builder
-	
 	Field errors:=New Stack<ErrorEx>
 
 	Field opts:BuildOpts
@@ -66,22 +72,32 @@ Class Builder
 	Method New( opts:BuildOpts )
 	
 		Self.opts=opts
-
-		instance=Self
 		
-		Local copts:=""
+		Builder=self
+
+		If opts.target="desktop" opts.target=HostOS
 		
 		ppsyms["__HOSTOS__"]="~q"+HostOS+"~q"
 		ppsyms["__TARGET__"]="~q"+opts.target+"~q"
 		ppsyms["__CONFIG__"]="~q"+opts.config+"~q"
 		
 		Select opts.target
-		Case "desktop"
-			profileName=HostOS+"_"+opts.config
-		Default
-			profileName=opts.target+"_"+opts.config
+		Case "windows","macos","linux"
+			ppsyms["__DESKTOP_TARGET__"]="true"
+			ppsyms["__WEB_TARGET__"]="false"
+			ppsyms["__MOBILE_TARGET__"]="false"
+		Case "emscripten"
+			ppsyms["__DESKTOP_TARGET__"]="false"
+			ppsyms["__WEB_TARGET__"]="true"
+			ppsyms["__MOBILE_TARGET__"]="false"
+		Case "android","ios"
+			ppsyms["__DESKTOP_TARGET__"]="false"
+			ppsyms["__WEB_TARGET__"]="false"
+			ppsyms["__MOBILE_TARGET__"]="true"
 		End
 		
+		profileName=opts.target+"_"+opts.config
+		
 		MODULES_DIR=CurrentDir()+"modules/"
 		
 		If opts.productType="app" APP_DIR=ExtractDir( opts.mainSource )
@@ -106,6 +122,8 @@ Class Builder
 		Select opts.target
 		Case "android"
 			product=New AndroidBuildProduct( module,opts )
+		Case "ios"
+			product=New IosBuildProduct( module,opts )
 		Default
 			product=New GccBuildProduct( module,opts )
 		End
@@ -263,6 +281,7 @@ Class Builder
 					Local ctype:=semantMembers.RemoveFirst()
 					
 					PNode.semanting.Push( ctype.cdecl )
+					Scope.semanting.Push( Null )
 					
 					Try
 					
@@ -272,12 +291,14 @@ Class Builder
 					End
 					
 					PNode.semanting.Pop()
+					Scope.semanting.Pop()
 
 				Else If Not semantStmts.Empty
 		
 					Local func:=semantStmts.Pop()
 					
 					PNode.semanting.Push( func.fdecl )
+					Scope.semanting.Push( Null )
 					
 					Try
 						func.SemantStmts()
@@ -286,6 +307,7 @@ Class Builder
 					End
 					
 					PNode.semanting.Pop()
+					Scope.semanting.Pop()
 				
 				Else
 					Exit

+ 228 - 189
src/mx2cc/buildproduct.monkey2

@@ -16,8 +16,8 @@ Class BuildProduct
 	Field OBJ_FILES:=New StringStack
 	Field LD_LIBS:=New StringStack
 	Field LD_SYSLIBS:=New StringStack
-	Field DLL_FILES:=New StringStack
 	Field ASSET_FILES:=New StringStack
+	Field DLL_FILES:=New StringStack
 	
 	Method New( module:Module,opts:BuildOpts )
 		Self.module=module
@@ -85,6 +85,8 @@ Class BuildProduct
 	
 	Method CopyAssets( assetsDir:String )
 	
+		If Not assetsDir.EndsWith( "/" ) assetsDir+="/"
+		
 		DeleteDir( assetsDir,True )
 		
 		CreateDir( assetsDir )
@@ -119,6 +121,42 @@ Class BuildProduct
 		CopyAssetFiles( assetFiles )
 	End
 
+	Method CopyDlls( dllsDir:String )
+	
+		If Not dllsDir.EndsWith( "/" ) dllsDir+="/"
+	
+		For Local src:=Eachin DLL_FILES
+		
+			Local dir:=dllsDir
+			
+			Local ext:=ExtractExt( src )
+			If ext
+				Local rdir:=GetEnv( "MX2_APP_DIR_"+ext.Slice( 1 ).ToUpper() )
+				If rdir 
+					dir=RealPath( dir+rdir )
+					If Not dir.EndsWith( "/" ) dir+="/"
+				Endif
+			Endif
+			
+			Local dst:=dir+StripDir( src )
+			
+			'FIXME! Hack for copying frameworks on macos!
+			'		
+#If __HOSTOS__="macos"
+			If ExtractExt( src ).ToLower()=".framework"
+				CreateDir( ExtractDir( dst ) )
+				If Not Exec( "rm -f -R "+dst ) Throw New BuildEx( "rm failed" )
+				If Not Exec( "cp -f -R "+src+" "+dst ) Throw New BuildEx( "cp failed" )
+				Continue
+			Endif
+#Endif
+			
+			If Not CopyAll( src,dst ) Throw New BuildEx( "Failed to copy '"+src+"' to '"+dst+"'" )
+			
+		Next
+	
+	End
+		
 	Private
 		
 	Method CopyAll:Bool( src:String,dst:String )
@@ -200,8 +238,6 @@ Class GccBuildProduct Extends BuildProduct
 	Field AS_CMD:="as"
 	Field LD_CMD:="g++"
 	
-	Field maxObjTime:Long
-
 	Method New( module:Module,opts:BuildOpts )
 		Super.New( module,opts )
 		
@@ -218,193 +254,223 @@ Class GccBuildProduct Extends BuildProduct
 			CXX_CMD="g++"
 			LD_CMD= "g++"
 			AS_CMD= "as"
+			If opts.target="ios" AS_CMD+=" -arch armv7"
 		End
 		
 	End
 	
-	Method Build() Override
+	Method CompileSource:String( src:String )
 
-		If opts.verbose=0 Print "Compiling...."
-		
-		If Not CreateDir( module.cacheDir ) Throw New BuildEx( "Error create dir '"+module.cacheDir+"'" )
-		
-		For Local src:=Eachin SRC_FILES
-		
-			Local obj:=module.cacheDir+MungPath( MakeRelativePath( src,module.cacheDir ) )+".o"
+		Local obj:=module.cacheDir+MungPath( MakeRelativePath( src,module.cacheDir ) )+".o"
 			
-			Local ext:=ExtractExt( src ).ToLower()
+		Local ext:=ExtractExt( src ).ToLower()
 						
-			Local cmd:="",isasm:=False
+		Local cmd:="",isasm:=False
 			
-			Select ext
-			Case ".c",".m"
+		Select ext
+		Case ".c",".m"
 			
-				cmd=CC_CMD+" "+CC_OPTS.Join( " " )
-				cmd+=" -I~q"+MODULES_DIR+"monkey/native~q"
-				cmd+=" -I~q"+MODULES_DIR+"~q"
-				If APP_DIR cmd+=" -I~q"+APP_DIR+"~q"
+			cmd=CC_CMD+" "+CC_OPTS.Join( " " )
+			cmd+=" -I~q"+MODULES_DIR+"monkey/native~q"
+			cmd+=" -I~q"+MODULES_DIR+"~q"
+			If APP_DIR cmd+=" -I~q"+APP_DIR+"~q"
 				
-			Case ".cc",".cxx",".cpp",".mm"
+		Case ".cc",".cxx",".cpp",".mm"
 
-				cmd=CXX_CMD+" "+CPP_OPTS.Join( " " )
-				cmd+=" -I~q"+MODULES_DIR+"monkey/native~q"
-				cmd+=" -I~q"+MODULES_DIR+"~q"
-				If APP_DIR cmd+=" -I~q"+APP_DIR+"~q"
+			cmd=CXX_CMD+" "+CPP_OPTS.Join( " " )
+			cmd+=" -I~q"+MODULES_DIR+"monkey/native~q"
+			cmd+=" -I~q"+MODULES_DIR+"~q"
+			If APP_DIR cmd+=" -I~q"+APP_DIR+"~q"
 
-			Case ".asm",".s"
+		Case ".asm",".s"
 			
-				cmd=AS_CMD
-				isasm=True
-			End
+			cmd=AS_CMD
+			isasm=True
+		End
 			
-			'Check dependancies
-			'			
-			Local objTime:=GetFileTime( obj )
+		'Check dependancies
+		'			
+		Local objTime:=GetFileTime( obj )
 			
-			Local deps:=StripExt( obj )+".deps"
+		Local deps:=StripExt( obj )+".deps"
 			
-			If opts.fast And objTime>=GetFileTime( src )	'source file up to date?
+		If opts.fast And objTime>=GetFileTime( src )	'source file up to date?
 			
-				Local uptodate:=True
+			Local uptodate:=True
 			
-				If Not isasm
+			If Not isasm
 			
-					If GetFileType( deps )=FILETYPE_NONE
+				If GetFileType( deps )=FILETYPE_NONE
 					
-						If opts.verbose>0 Print "Scanning "+src
+					If opts.verbose>0 Print "Scanning "+src
 				
-						Exec( cmd+" -MM ~q"+src+"~q >~q"+deps+"~q" ) 
+					Exec( cmd+" -MM ~q"+src+"~q >~q"+deps+"~q" ) 
 						
-					Endif
+				Endif
 					
-					Local srcs:=LoadString( deps ).Split( " \" )
+				Local srcs:=LoadString( deps ).Split( " \" )
 					
-					For Local i:=1 Until srcs.Length
+				For Local i:=1 Until srcs.Length
 					
-						Local src:=srcs[i].Trim().Replace( "\ "," " )
+					Local src:=srcs[i].Trim().Replace( "\ "," " )
 					
-						If GetFileTime( src )>objTime
-							uptodate=False
-							Exit
-						Endif
+					If GetFileTime( src )>objTime
+						uptodate=False
+						Exit
+					Endif
 						
-					Next
+				Next
 				
-				Endif
+			Endif
 				
-				If uptodate
-					maxObjTime=Max( maxObjTime,objTime )
-					OBJ_FILES.Push( obj )
-					Continue
-				Endif
+			If uptodate Return obj
 				
-			Else
+		Else
 			
-				DeleteFile( deps )
+			DeleteFile( deps )
 
-			Endif
+		Endif
 			
-			If opts.verbose>0 Print "Compiling "+src
+		If opts.verbose>0 Print "Compiling "+src
 			
-			If Not isasm cmd+=" -c"
+		If Not isasm cmd+=" -c"
 			
-			cmd+=" -o ~q"+obj+"~q ~q"+src+"~q"
+		cmd+=" -o ~q"+obj+"~q ~q"+src+"~q"
 			
-			Exec( cmd )
+		Exec( cmd )
+		
+		Return obj
+	End
+	
+	Method Build() Override
+	
+		If opts.verbose=0 Print "Compiling..."
+		
+		If Not CreateDir( module.cacheDir ) Throw New BuildEx( "Error create dir '"+module.cacheDir+"'" )
+
+		For Local src:=Eachin SRC_FILES
+			
+			OBJ_FILES.Push( CompileSource( src ) )
+			
+		Next
+
+		If opts.productType="module"
 			
+			BuildArchive()
+			
+		Else
+			
+			BuildApp()
+			
+		Endif
+		
+	End
+	
+	Method BuildArchive:String()
+
+		Local outputFile:=module.outputDir+module.name+".a"
+		
+		'AR is slow! This is probably not quite right, but it'll do for now...
+		'
+		Local maxObjTime:Long
+		For Local obj:=Eachin OBJ_FILES
 			maxObjTime=Max( maxObjTime,GetFileTime( obj ) )
+		Next
+		If GetFileTime( outputFile )>maxObjTime Return outputFile
+		
+		If opts.verbose>=0 Print "Archiving "+outputFile+"..."
+		
+		DeleteFile( outputFile )
+		
+		Local objs:=""
+		
+		For Local i:=0 Until OBJ_FILES.Length
+			
+			objs+=" ~q"+OBJ_FILES.Get( i )+"~q"
+			
+			If objs.Length<1000 And i<OBJ_FILES.Length-1 Continue
+
+			Local cmd:=AR_CMD+" q ~q"+outputFile+"~q"+objs
+
+			Exec( cmd )
 			
-			OBJ_FILES.Push( obj )
+			objs=""
 			
 		Next
-	
-		Select opts.productType
-		Case "app"
-			CreateApp()
-		Case "module"
-			CreateArchive()
-		End
-	
+		
+		Return outputFile
+		
 	End
 	
-	Method CreateApp()
+	Method BuildApp() Virtual
 	
-		Local assetsDir:="",dllsDir:=""
+		outputFile=opts.product
+		If Not outputFile outputFile=module.outputDir+module.name
 		
+		Local assetsDir:=ExtractDir( outputFile )+"assets/"
+		Local dllsDir:=ExtractDir( outputFile )
+
 		Local cmd:=LD_CMD
 		cmd+=" "+LD_OPTS.Join( " " )
 		
-		If opts.target="desktop" And HostOS="windows"
+		Select opts.target
+		Case "windows"
 		
-			If opts.appType="gui" cmd+=" -mwindows"
+			If ExtractExt( outputFile ).ToLower()<>".exe" outputFile+=".exe"
 		
-			outputFile=module.outputDir+module.name+".exe"
-			assetsDir=module.outputDir+"assets/"
-			dllsDir=ExtractDir( outputFile )
+			If opts.appType="gui" cmd+=" -mwindows"
 			
-		Else If opts.target="desktop" And HostOS="macos"
+		Case "macos"
 		
 			If opts.appType="gui"
 			
-				Local productName:=module.name
-	
-				Local outputDir:=module.outputDir+module.name+".app/"
+				Local appDir:=outputFile
+				If ExtractExt( appDir ).ToLower()<>".app" appDir+=".app"
+				appDir+="/"
 				
-				outputFile=outputDir+"Contents/MacOS/"+module.name
-				assetsDir=outputDir+"Contents/Resources/"
-				dllsDir=ExtractDir( outputFile )
-				
-				CreateDir( outputDir )
-				CreateDir( outputDir+"Contents" )
-				CreateDir( outputDir+"Contents/MacOS" )
-				CreateDir( outputDir+"Contents/Resources" )
+				Local appName:=StripExt( StripDir( outputFile ) )
 				
-				Local plist:=""
-				plist+="<?xml version=~q1.0~q encoding=~qUTF-8~q?>~n"
-				plist+="<!DOCTYPE plist PUBLIC ~q-//Apple Computer//DTD PLIST 1.0//EN~q ~qhttp://www.apple.com/DTDs/PropertyList-1.0.dtd~q>~n"
-				plist+="<plist version=~q1.0~q>~n"
-				plist+="<dict>~n"
-				plist+="~t<key>CFBundleExecutable</key>~n"
-				plist+="~t<string>"+productName+"</string>~n"
-				plist+="~t<key>CFBundleIconFile</key>~n"
-				plist+="~t<string>"+productName+"</string>~n"
-				plist+="~t<key>CFBundlePackageType</key>~n"
-				plist+="~t<string>APPL</string>~n"
-				plist+="</dict>~n"
-				plist+="</plist>~n"
+				outputFile=appDir+"Contents/MacOS/"+appName
+				assetsDir=appDir+"Contents/Resources/"
+				dllsDir=ExtractDir( outputFile )
 				
-				SaveString( plist,outputDir+"Contents/Info.plist" )
+				If GetFileType( appDir )=FileType.None
+
+					CreateDir( appDir )
+					CreateDir( appDir+"Contents" )
+					CreateDir( appDir+"Contents/MacOS" )
+					CreateDir( appDir+"Contents/Resources" )
+					
+					Local plist:=""
+					plist+="<?xml version=~q1.0~q encoding=~qUTF-8~q?>~n"
+					plist+="<!DOCTYPE plist PUBLIC ~q-//Apple Computer//DTD PLIST 1.0//EN~q ~qhttp://www.apple.com/DTDs/PropertyList-1.0.dtd~q>~n"
+					plist+="<plist version=~q1.0~q>~n"
+					plist+="<dict>~n"
+					plist+="~t<key>CFBundleExecutable</key>~n"
+					plist+="~t<string>"+appName+"</string>~n"
+					plist+="~t<key>CFBundleIconFile</key>~n"
+					plist+="~t<string>"+appName+"</string>~n"
+					plist+="~t<key>CFBundlePackageType</key>~n"
+					plist+="~t<string>APPL</string>~n"
+					plist+="</dict>~n"
+					plist+="</plist>~n"
+					
+					SaveString( plist,appDir+"Contents/Info.plist" )
 				
-			Else
-			
-				outputFile=module.outputDir+module.name
-				assetsDir=module.outputDir+"assets/"
-				dllsDir=ExtractDir( outputFile )
+				Endif
 			
 			Endif
-			
-		Else If opts.target="desktop" And HostOS="linux"
 		
-			outputFile=module.outputDir+module.name
+		Case "emscripten"
+
 			assetsDir=module.outputDir+"assets/"
-			dllsDir=ExtractDir( outputFile )
 			
-		Else If opts.target="emscripten"
-		
-			outputFile=module.outputDir+module.name+".html"
-			assetsDir=module.outputDir+"assets/"
-			dllsDir=ExtractDir( outputFile )
+			If ExtractExt( outputFile ).ToLower()<>".html" outputFile+=".html"
 			
-'			Note: mserver can't handle --emrun as it tries to POST stdout
-'			cmd="em++ --emrun --preload-file ~q"+assetsDir+"@/assets~q"
-
 			cmd+=" --preload-file ~q"+assetsDir+"@/assets~q"
-			
-		Endif
-		
-		If opts.verbose>=0 Print "Linking "+outputFile
+		End
 		
-		CopyAssets( assetsDir )
+		If opts.verbose>=0 Print "Linking "+outputFile+"..."
 		
 		cmd+=" -o ~q"+outputFile+"~q"
 		
@@ -420,7 +486,7 @@ Class GccBuildProduct Extends BuildProduct
 	
 		lnkFiles+=" "+LD_SYSLIBS.Join( " " )
 		
-		If HostOS="windows" And opts.target="desktop"
+		If opts.target="windows"
 			Local tmp:=AllocTmpFile( "lnkFiles" )
 			SaveString( lnkFiles,tmp )
 			cmd+=" -Wl,@"+tmp
@@ -428,70 +494,13 @@ Class GccBuildProduct Extends BuildProduct
 			cmd+=lnkFiles
 		Endif
 
-		Exec( cmd )
-		
-		For Local src:=Eachin DLL_FILES
+		CopyAssets( assetsDir )
 		
-			Local dir:=dllsDir
-			
-			Local ext:=ExtractExt( src )
-			If ext
-				Local rdir:=GetEnv( "MX2_APP_DIR_"+ext.Slice( 1 ).ToUpper() )
-				If rdir dir=RealPath( dir+rdir )
-			Endif
-			
-			If Not dir.EndsWith( "/" ) dir+="/"
-			
-			Local dst:=dir+StripDir( src )
-			
-			'FIXME! Hack for copying frameworks on macos!
-			'		
-#If __HOSTOS__="macos"
-			If ExtractExt( src ).ToLower()=".framework"
-				CreateDir( ExtractDir( dst ) )
-				If Not Exec( "rm -f -R "+dst ) Throw New BuildEx( "rm failed" )
-				If Not Exec( "cp -f -R "+src+" "+dst ) Throw New BuildEx( "cp failed" )
-				Continue
-			Endif
-#Endif
-			
-			If Not CopyAll( src,dst ) Throw New BuildEx( "Failed to copy '"+src+"' to '"+dst+"'" )
-			
-		Next
+		CopyDlls( dllsDir )
 		
+		Exec( cmd )
 	End
 	
-	Method CreateArchive:String()
-
-		Local outputFile:=module.outputDir+module.name+".a"
-		
-		'AR is slow! This is probably not quite right, but it'll do for now...
-		If GetFileTime( outputFile )>maxObjTime Return outputFile
-		
-		If opts.verbose>=0 Print "Archiving "+outputFile
-		
-		DeleteFile( outputFile )
-		
-		Local objs:=""
-		
-		For Local i:=0 Until OBJ_FILES.Length
-			
-			objs+=" ~q"+OBJ_FILES.Get( i )+"~q"
-			
-			If objs.Length<1000 And i<OBJ_FILES.Length-1 Continue
-
-			Local cmd:=AR_CMD+" q ~q"+outputFile+"~q"+objs
-
-			Exec( cmd )
-			
-			objs=""
-			
-		Next
-		
-		Return outputFile
-		
-	End
-
 	Method Run() Override
 	
 		Local run:=""
@@ -507,7 +516,35 @@ Class GccBuildProduct Extends BuildProduct
 	End
 	
 End
+
+Class IosBuildProduct Extends GccBuildProduct
+
+	Method New( module:Module,opts:BuildOpts )
+		Super.New( module,opts )
+	End
+	
+	Method BuildApp() Override
+	
+		Local arc:=BuildArchive()
+		
+		Local outputFile:=module.outputDir+"libmx2_main.a"
+		
+		Local cmd:="libtool -static -o ~q"+outputFile+"~q ~q"+arc+"~q"
+		
+		For Local lib:=Eachin LD_LIBS
+			cmd+=" ~q"+lib+"~q"
+		Next
+		
+		Print "cmd="+cmd
+		
+		Exec( cmd )
+	End
 	
+	Method Run() Override
+	End
+	
+End
+
 Class AndroidBuildProduct Extends BuildProduct
 
 	Method New( module:Module,opts:BuildOpts )
@@ -544,7 +581,7 @@ Class AndroidBuildProduct Extends BuildProduct
 		
 		If opts.productType="app"
 		
-			For Local extmod:=Eachin Builder.instance.modules
+			For Local extmod:=Eachin Builder.modules
 				If extmod=module continue
 			
 				Local src:=extmod.outputDir+"obj/local/$(TARGET_ARCH_ABI)/libmx2_"+extmod.name+".a"
@@ -591,7 +628,7 @@ Class AndroidBuildProduct Extends BuildProduct
 		If opts.productType="app"
 		
 			buf.Push( "LOCAL_STATIC_LIBRARIES := \" )
-			For Local extmod:=Eachin Builder.instance.modules.Backwards()
+			For Local extmod:=Eachin Builder.modules.Backwards()
 				If extmod=module Continue
 				
 				buf.Push( "mx2_"+extmod.name+" \" )
@@ -629,9 +666,11 @@ Class AndroidBuildProduct Extends BuildProduct
 		
 		ChangeDir( cd )
 		
-		If opts.productType="app"
+		If opts.productType="app" And opts.assets And opts.dlls
 		
-			CopyAssets( module.outputDir+"assets/" )
+			CopyDir( module.outputDir+"libs",opts.dlls )
+
+			CopyAssets( opts.assets )
 		
 		Endif
 		

+ 114 - 58
src/mx2cc/class.monkey2

@@ -4,16 +4,8 @@ Namespace mx2
 Class ClassDecl Extends Decl
 
 	Field genArgs:String[]
-	Field superType:TypeExpr
-	Field ifaceTypes:TypeExpr[]
-	
-	Method ToString:String() Override
-		Local str:=Super.ToString()
-		If genArgs str+="<"+",".Join( genArgs )+">"
-		If superType str+=" extends "+superType.ToString()
-		If ifaceTypes str+=" implements "+Join( ifaceTypes )
-		Return str
-	End
+	Field superType:Expr
+	Field ifaceTypes:Expr[]
 	
 	Method ToNode:SNode( scope:Scope ) Override
 	
@@ -25,6 +17,16 @@ Class ClassDecl Extends Decl
 		Return New ClassType( Self,scope,types,Null )
 	End
 	
+	Method ToString:String() Override
+		Local str:=Super.ToString()
+		If genArgs str+="<"+",".Join( genArgs )+">"
+		If superType str+=" Extends "+superType.ToString()
+		If ifaceTypes 
+			If kind="interface" str+=" Extends "+Join( ifaceTypes ) Else str+=" Implements "+Join( ifaceTypes )
+		Endif
+		Return str
+	End
+	
 End
 
 Class ClassType Extends Type
@@ -128,7 +130,8 @@ Class ClassType Extends Type
 		If cdecl.superType
 		
 			Try
-				Local type:=cdecl.superType.Semant( scope )
+				Local type:=cdecl.superType.SemantType( scope )
+
 				If TCast<VoidType>( type )
 				
 					If Not cdecl.IsExtern Or cdecl.kind<>"class" Throw New SemantEx( "Only extern classes can extend 'Void'" )
@@ -167,7 +170,8 @@ Class ClassType Extends Type
 			For Local iface:=Eachin cdecl.ifaceTypes
 			
 				Try
-					Local type:=iface.Semant( scope )
+					Local type:=iface.SemantType( scope )
+
 					Local ifaceType:=TCast<ClassType>( 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" )
@@ -199,20 +203,18 @@ Class ClassType Extends Type
 		
 		Endif
 		
-		Local builder:=Builder.instance
-		
 		If scope.IsGeneric Or cdecl.IsExtern
 		
-			builder.semantMembers.AddLast( Self )
+			Builder.semantMembers.AddLast( Self )
 			
 		Else
 		
 			If IsGenInstance
 				SemantMembers()
-				Local module:=builder.semantingModule 
+				Local module:=Builder.semantingModule 
 				module.genInstances.Push( Self )
 			Else
-				builder.semantMembers.AddLast( Self )
+				Builder.semantMembers.AddLast( Self )
 			Endif
 			
 			transFile.classes.Push( Self )
@@ -391,28 +393,41 @@ Class ClassType Extends Type
 		Return Null
 	End
 	
-	'***** Type overrides *****
-
-	Method FindNode:SNode( ident:String ) Override
-	
+	Method FindNode2:SNode( ident:String )
 		If membersSemanting SemantError( "ClassType.FindNode() class='"+ToString()+"', ident='"+ident+"'" )
 	
 		Local node:=scope.GetNode( ident )
 		If node Or ident="new" Return node
 		
-		If superType Return superType.FindNode( ident )
+		If superType Return superType.FindNode2( ident )
+		Return Null
+	End
+
+	Method FindType2:Type( ident:String )
+	
+		Local type:=scope.GetType( ident )
+		If type Return type
 		
+		If superType Return superType.FindType2( ident )
 		Return Null
 	End
+
+	'***** Type overrides *****
+	
+	Method FindNode:SNode( ident:String ) Override
+	
+		Local node:=FindNode2( ident )
+		If node Return node
+		
+		Return FileScope.FindExtension( ident,False,Self )
+	End
 		
 	Method FindType:Type( ident:String ) Override
 	
-		Local type:=scope.GetType( ident )
+		Local type:=FindType2( ident )
 		If type Return type
 		
-		If superType Return superType.FindType( ident )
-		
-		Return Null
+		Return Cast<Type>( FileScope.FindExtension( ident,True,Self ) )
 	End
 	
 	Method Index:Value( args:Value[],value:Value ) Override
@@ -426,18 +441,16 @@ Class ClassType Extends Type
 	'
 	Method GenInstance:Type( types:Type[] ) Override
 			
-		'FIXME! This is (minaly) so code can generate C<T2> inside class C<T>
+		'FIXME! This is (mainly) so code can generate C<T2> inside class C<T>
 		'
 		If instanceOf Return instanceOf.GenInstance( types )
 
-		If Not IsGeneric
-
-			Throw New SemantEx( "Class '"+ToString()+"' is not generic" )
-
-		Endif
+		If Not IsGeneric Throw New SemantEx( "Class '"+ToString()+"' is not generic" )
 
 		If types.Length<>Self.types.Length Throw New SemantEx( "Wrong number of generic type parameters" )
 
+'		If AnyTypeGeneric( types ) Return Self
+
 		If Not instances instances=New Stack<ClassType>
 	
 		For Local inst:=Eachin instances
@@ -452,28 +465,33 @@ Class ClassType Extends Type
 		Return inst
 	End
 	
-	Method DistanceToType:Int( type:Type ) Override
+	Method FindToFunc:FuncValue( type:Type )
 	
-		If type=Self Return 0
+		Local flist:=Cast<FuncList>( FindNode( "to" ) )
+		If Not flist Return Null
 		
-		'cast anything to bool
-		If type=BoolType 
-			If IsClass Or IsInterface Return MAX_DISTANCE
-			Return -1
-		Endif
-
-		#rem
-		'cast native classes to void ptr		
-		Local ptype:=TCast<PointerType>( type )
-		If ptype 
-			If IsVoid And ptype.elemType=Type.VoidType Return MAX_DISTANCE
-			Return -1
+		Return overload.FindOverload( flist.funcs,type,Null )
+		
+		#rem		
+		
+		If flist
+			Local func:=overload.FindOverload( flist.funcs,type,Null )
+			If func Return func
 		Endif
+		
+		flist=Cast<FuncList>( FileScope.FindExtension( "to",False,Self ) )
+		If Not flist Return Null
+		
+		Return overload.FindOverload( flist.funcs,type,Null )
 		#end
 		
+	End
+	
+	Method DistanceToBase:Int( type:Type )
+	
 		Local ctype:=TCast<ClassType>( type )
 		If Not ctype Return -1
-	
+
 		Local dist:=0
 		Local stype:=Self
 		
@@ -493,12 +511,57 @@ Class ClassType Extends Type
 		
 		Return -1
 	End
+	
+	Method DistanceToType:Int( type:Type ) Override
+	
+		If type=Self Return 0
 
-	Method ExtendsType:Bool( type:Type ) Override
+		'Cast to super class
+		Local dist:=DistanceToBase( type )
+		If dist>=0 Return dist
+		
+		'Cast to bool
+		If type=BoolType 
+			If IsClass Or IsInterface Return MAX_DISTANCE
+			Return -1
+		Endif
+
+		'Operator To:
+		Local func:=FindToFunc( type )
+		If func Return MAX_DISTANCE
+		
+		Return -1
+
+		#rem
+		'cast native classes to void ptr		
+		Local ptype:=TCast<PointerType>( type )
+		If ptype 
+			If IsVoid And ptype.elemType=Type.VoidType Return MAX_DISTANCE
+			Return -1
+		Endif
+		#end
+	End
+	
+	Method UpCast:Value( rvalue:Value,type:Type ) Override
 	
-		Local t:=DistanceToType( type )
+		'Cast to superclass
+		Local dist:=DistanceToBase( type )
+		If dist>=0 Return New UpCastValue( type,rvalue )
+		
+		'Cast to bool
+		If type=BoolType Return New UpCastValue( type,rvalue )
 		
-		Return t>=0 And t<MAX_DISTANCE
+		'Operator To:
+		Local func:=FindToFunc( type )
+		If func Return func.ToValue( rvalue ).Invoke( Null )
+
+		Throw New SemantEx( "Unable to convert value from type '"+rvalue.type.ToString()+"' to type '"+type.ToString()+"'" )
+		Return Null
+	End
+
+	Method ExtendsType:Bool( type:Type ) Override
+	
+		Return DistanceToBase( type )>=0
 	End
 	
 	Method CanCastToType:Bool( type:Type ) Override
@@ -578,13 +641,6 @@ Class OpIndexValue Extends Value
 		Return invokeGet
 	End
 	
-	#rem
-	Method UpCast:Value( type:Type ) Override
-	
-		Return ToRValue().UpCast( type )
-	End
-	#end
-	
 	Method Assign:Stmt( pnode:PNode,op:String,rvalue:Value,block:Block ) Override
 		
 		If Not setters Throw New SemantEx( "Value cannot be index assigned" )
@@ -701,7 +757,7 @@ Class ClassScope Extends Scope
 	
 	Method FindType:Type( ident:String ) Override
 	
-		If ident=ctype.cdecl.ident
+		If ident=ctype.cdecl.ident And Not ctype.cdecl.IsExtension
 			If Not itype
 				If ctype.types And Not ctype.instanceOf
 					itype=ctype.GenInstance( ctype.types )

+ 8 - 14
src/mx2cc/decl.monkey2

@@ -91,24 +91,14 @@ Class Decl Extends PNode
 		Return (flags & DECL_DEFAULT)<>0
 	End
 	
-	Method ToString:String() Override
-		Return kind.Capitalize()+" "+ident
-	End
-	
-	Method Emit( buf:StringStack,spc:String ) Virtual
-	
-		buf.Push( spc+ToString() )
-		
-		spc+="  "
-		For Local member:=Eachin members
-			member.Emit( buf,spc )
-		Next
-	End
-	
 	Method ToNode:SNode( scope:Scope ) Virtual
 		Return Null
 	End
 
+	Method ToString:String() Override
+		Return kind.Capitalize()+" "+ident
+	End
+	
 End
 
 Class FileDecl Extends Decl
@@ -128,5 +118,9 @@ Class FileDecl Extends Decl
 	Field classes:=New Stack<ClassType>
 	Field globals:=New Stack<VarValue>
 	Field functions:=New Stack<FuncValue>
+	
+	Method ToString:String() Override
+		Return "~q"+path+"~q"
+	End
 
 End

+ 1 - 1
src/mx2cc/docs/markdownbuffer.monkey2

@@ -214,7 +214,7 @@ Class MarkdownBuffer
 		_return=""
 		_label=""
 		
-		Local docs:=hoedown.MarkdownToHtml( markdown )
+		Local docs:=minimarkdown.MarkdownToHtml( markdown )
 		
 		Return docs
 	End

+ 489 - 0
src/mx2cc/docs/minimarkdown.monkey2

@@ -0,0 +1,489 @@
+
+Namespace mx2.docs.minimarkdown
+
+Class MarkdownConvertor
+
+	Const CHAR_HASH:=35		'#
+	Const CHAR_ESCAPE:=92	'\
+
+	Method New( src:String )
+	
+		_src=src
+		_lines=_src.Split( "~n" )
+		
+		For Local i:=0 Until _lines.Length
+			_lines[i]=_lines[i].TrimEnd()
+		Next
+		
+	End
+	
+	Method ToHtml:String()
+	
+		While Not AtEnd
+		
+			Local line:=NextLine()
+		
+			If line.StartsWith( "#" )
+			
+				EmitHeader( line )
+			
+			Else If line.StartsWith( "|" )
+			
+				EmitTable( line )
+				
+			Else If line.StartsWith( "*" )
+			
+				EmitList( line )
+				
+			Else If line.StartsWith( "```" )
+			
+				EmitCode( line )
+				
+			Else If line.StartsWith( "---" )
+			
+				Emit( "<hr>" )
+				
+			Else If line.StartsWith( "<" )
+			
+				Emit( line+"\" )
+				
+			Else If line
+			
+				If _lineNum>1 And _lines[_lineNum-2]=""
+					Emit( "<p>"+Escape( line ) )
+				Else
+					Emit( Escape( line ) )
+				Endif
+
+			Else
+			
+'				If Not _buf.Empty And _buf.Top<>"<p>" Emit( "<p>" )
+				
+			Endif
+				
+'			Else 
+			
+'				If _buf.Empty Or _buf.Top="" Emit( "<p>" )
+			
+'				Emit( Escape( line ) )
+			
+'			Endif
+			
+		Wend
+		
+		Local html:=_buf.Join( "~n" )
+		
+		html=html.Replace( "\~n","" )
+		
+		Return html
+	
+	End
+
+	Private
+	
+	Field _src:String
+	Field _lines:String[]
+	
+	Field _lineNum:=0
+	Field _buf:=New StringStack
+	
+	Property AtEnd:Bool()
+		Return _lineNum>=_lines.Length
+	End
+	
+	Method Emit( str:String )
+		_buf.Push( str )
+	End
+
+	Method NextLine:String()
+		Local line:=_lineNum>=0 And _lineNum<_lines.Length ? _lines[_lineNum] Else ""
+		_lineNum+=1
+		Return line
+	End
+	
+	Method PrevLine:String()
+		_lineNum-=1
+		Local line:=_lineNum>=0 And _lineNum<_lines.Length ? _lines[_lineNum] Else ""
+		Return line
+	End
+	
+	Method Find:Int( str:String,chr:String,index:Int=0 )
+
+		Repeat
+			Local i:=str.Find( chr,index )
+			If i=-1 Return str.Length
+			If i=0 Or str[i-1]<>CHAR_ESCAPE Return i
+			index=i+1
+		Forever
+		
+		Return str.Length
+	End
+	
+	Method ReplaceAll:String( str:String,find:String,rep:String,index:Int )
+	
+		Local i0:=index
+		
+		Repeat
+		
+			Local i1:=str.Find( find,i0 )
+			If i1=-1 Exit
+			
+			str=str.Slice( 0,i1 )+rep+str.Slice( i1+find.Length )
+			i0=i1+rep.Length
+		
+		Forever
+		
+		Return str
+	End
+	
+	Method EscapeHtml:String( str:String )
+	
+		'str=str.Replace( "&","&amp;" )
+		Local i0:=0
+		Repeat
+		
+			Local i1:=str.Find( "&",i0 )
+			If i1=-1 Exit
+
+			Const tags:=New String[]( "nbsp;" )
+
+			For Local tag:=Eachin tags
+				If str.Slice( i1+1,i1+1+tag.Length )<>tag Continue
+				i0=i1+1+tag.Length
+				Exit
+			Next
+			If i0>i1 Continue
+			
+			Local r:="&amp;"
+			str=str.Slice( 0,i1 )+r+str.Slice( i1+1 )
+			i0=i1+r.Length
+		Forever
+		
+		'str=str.Replace( "<","&lt;" )
+		'str=str.Replace( ">","&gt;" )
+		i0=0
+		Repeat
+		
+			Local i1:=str.Find( "<",i0 )
+			If i1=-1 
+				str=ReplaceAll( str,">","&gt;",i0 )
+				Exit
+			Endif
+			
+			Local i2:=str.Find( ">",i1+1 )
+			If i2=-1
+				str=ReplaceAll( str,"<","&lt;",i0 )
+				str=ReplaceAll( str,">","&gt;",i0 )
+				Exit
+			Endif
+			
+			Const tags:=New String[]( "a href=","/a" )
+			
+			For Local tag:=Eachin tags
+				If str.Slice( i1+1,i1+1+tag.Length )<>tag Continue
+				
+				Local r:=str.Slice( i1+1,i2 )
+
+				r=r.Replace( "\","\\" )
+				r=r.Replace( "*","\*" )
+				r=r.Replace( "_","\_" )
+				r=r.Replace( "`","\`" )
+				
+				r="<"+r+">"
+
+				str=str.Slice( 0,i1 )+r+str.Slice( i2+1 )
+				i0=i1+r.Length
+				Exit
+			Next
+			If i0>i1 Continue
+			
+			Local r:="&lt;"+str.Slice( i1+1,i2 )+"&gt;"
+			str=str.Slice( 0,i1 )+r+str.Slice( i2+1 )
+			i0=i1+r.Length
+		Forever
+			
+		Return str
+	End
+	
+	Method ConvertSpanTags:String( str:String,tag:String,ent:String )
+	
+		Local op:="<"+ent+">"
+		Local cl:="</"+ent+">"
+	
+		Local i0:=0
+		Repeat
+		
+			Local i1:=Find( str,tag,i0 )
+			If i1=str.Length Return str
+			
+			Local i2:=Find( str,tag,i1+1 )
+			If i2=str.Length Return str
+			
+			Local r:=op+str.Slice( i1+1,i2 )+cl
+			
+			str=str.Slice( 0,i1 )+r+str.Slice( i2+1 )
+			i0=i1+r.Length
+		
+		Forever
+		
+		Return str
+	End
+	
+	#rem
+	Method ConvertSpanHtml:String( str:String )
+	
+		Local i0:=0
+		Repeat
+
+			Local i1:=Find( str,"[",i0 )
+			If i1=str.Length Return str
+			
+			Local i2:=Find( str,"]",i1+1 )
+			If i2=str.Length Return str
+
+			Local is:=i1+1
+			While is<i2 And IsAlpha( str[is] )
+				is+=1
+			Wend
+			If is=i1+1
+				i0=i2+1
+				Continue
+			End
+			Local id:=str.Slice( i1+1,is )
+			
+			Local i3:=Find( str,"[/"+id+"]",i2+1 )
+			If i3=str.Length 
+				i0=i2+1
+				Continue
+			Endif
+			
+			Local args:=str.Slice( is,i2 )
+
+			args=args.Replace( "\","\\" )
+			args=args.Replace( "*","\*" )
+			args=args.Replace( "_","\_" )
+			args=args.Replace( "`","\`" )
+			
+			Local r:="<"+id+args+">"+str.Slice( i2+1,i3 )+"</"+id+">"
+			
+			str=str.Slice( 0,i1 )+r+str.Slice( i3+id.Length+3 )
+			
+			i0=i1+r.Length
+			
+		Forever
+		
+		Return str
+	End
+	
+	Method ConvertSpanLinks:String( str:String )
+	
+		Local i0:=0
+
+		Repeat
+		
+			Local i1:=Find( str,"[",i0 )
+			If i1=str.Length Return str
+			
+			Local i2:=Find( str,"](",i1+1 )
+			If i2=str.Length 
+				i0=i1+1
+				Continue
+			Endif
+			
+			Local i3:=Find( str,")",i2+2 )
+			If i3=str.Length
+				i0=i2+2
+				Continue
+			Endif
+			
+			Local text:=str.Slice( i1+1,i2 )
+			Local href:=str.Slice( i2+2,i3 )
+			
+			href=href.Replace( "\","\\" )
+			href=href.Replace( "*","\*" )
+			href=href.Replace( "_","\_" )
+			href=href.Replace( "`","\`" )
+			
+			Local r:="<a href=~q"+href+"~q>"+text+"</a>"
+			
+			str=str.Slice( 0,i1 )+r+str.Slice( i3+1 )
+			i0=i1+r.Length
+			
+		Forever
+		
+		Return str
+	End
+	#end
+	
+	Method ConvertEscapeChars:String( str:String )
+	
+		Local i0:=0
+
+		Repeat
+			Local i1:=str.Find( "\",i0 )
+			If i1=-1 Or i1+1=str.Length  Return str
+			str=str.Slice( 0,i1 )+str.Slice( i1+1 )
+			i0=i1+1
+		Forever
+		
+		Return str
+	End
+	
+	Method Escape:String( str:String )
+	
+		str=EscapeHtml( str )
+		
+		'str=ConvertSpanHtml( str )
+		'str=ConvertSpanLinks( str )
+		
+		str=ConvertSpanTags( str,"*","b" )
+		str=ConvertSpanTags( str,"_","i" )
+		str=ConvertSpanTags( str,"`","code" )
+		
+		str=ConvertEscapeChars( str )
+		
+		Return str
+	End
+	
+	Method EmitHeader( line:String )
+
+		Local i:=1
+		While i<line.Length
+			If line[i]<>CHAR_HASH Exit
+			i+=1
+		Wend
+				
+		Emit( "<h"+i+">" )
+		Emit( Escape( line.Slice( i ).TrimStart() ) )
+		Emit( "</h"+i+">" )
+	End
+	
+	Method EmitTable( line:String )
+
+		Local head:=line
+		Local align:=NextLine()
+				
+		If Not align.StartsWith( "|" )
+			Emit( Escape( head ) )
+			PrevLine()
+			Return
+		Endif
+			
+		Local heads:=New StringStack
+		Local aligns:=New StringStack
+				
+		Local i0:=1
+		While i0<head.Length
+			Local i1:=Find( head,"|",i0 )
+			heads.Push( Escape( head.Slice( i0,i1 ).TrimStart() ) )
+			i0=i1+1
+		Wend
+				
+		i0=1
+		While i0<align.Length
+			Local i1:=Find( align,"|",i0 )
+			Local t:=align.Slice( i0,i1 )
+			If t.StartsWith( ":-" )
+				If t.EndsWith( "-:" )
+					aligns.Push( "center" )
+				Else
+					aligns.Push( "left" )
+				Endif
+			Else If t.EndsWith( "-:" )
+				aligns.Push( "right" )
+			Else
+				aligns.Push( "center" )
+			Endif
+			i0=i1+1
+		Wend
+				
+		While aligns.Length<heads.Length
+			aligns.Push( "center" )
+		Wend
+				
+		Emit( "<table>" )
+
+		Emit( "<tr>" )
+		For Local i:=0 Until heads.Length
+			Emit( "<th style=~qtext-align:"+aligns[i]+"~q>"+heads[i]+"</th>" )
+		Next
+		Emit( "</tr>" )
+				
+		Repeat
+			Local row:=NextLine()
+			If Not row.StartsWith( "|" ) 
+				PrevLine()
+				Exit
+			Endif
+					
+			Emit( "<tr>" )
+			Local i0:=1,col:=0
+			While i0<row.Length And col<heads.Length
+				Local i1:=Find( row,"|",i0 )
+				Emit( "<td style=~qtext-align:"+aligns[col]+"~q>"+Escape( row.Slice( i0,i1 ).TrimStart() )+"</td>" )
+				i0=i1+1
+				col+=1
+			Wend
+			Emit( "</tr>" )
+		Forever
+				
+		Emit( "</table>" )
+		
+	End
+	
+	Method EmitList( line:String )
+	
+		Local kind:=line.Slice( 0,1 )
+		
+		Select kind
+		Case "*" Emit( "<ul>" )
+		Case "+" Emit( "<ol>" )
+		End
+		
+		Repeat
+		
+			Emit( "<li>"+Escape( line.Slice( 1 ) )+"</li>" )
+			
+			If AtEnd Exit
+		
+			line=NextLine()
+			If line.StartsWith( kind ) Continue
+			
+			PrevLine()
+			Exit
+
+		Forever
+		
+		Select kind
+		Case "*" Emit( "</ul>" )
+		Case "+" Emit( "</ol>" )
+		End
+	
+	End
+	
+	Method EmitCode( line:String )
+	
+		Emit( "<pre><code>\" )
+	
+		While Not AtEnd
+		
+			line=NextLine()
+			If line.StartsWith( "```" ) Exit
+			
+			Emit( EscapeHtml( line ) )
+			
+		Wend
+		
+		Emit( "</code></pre>" )
+	
+	End
+	
+End
+
+Function MarkdownToHtml:String( markdown:String )
+
+	Local convertor:=New MarkdownConvertor( markdown )
+	
+	Return convertor.ToHtml()
+
+End

+ 0 - 2
src/mx2cc/enum.monkey2

@@ -3,8 +3,6 @@ Namespace mx2
 
 Class EnumDecl Extends Decl
 
-	Field superType:TypeExpr
-
 	Method ToNode:SNode( scope:Scope ) Override
 	
 		Return New EnumType( Self,scope )

+ 1 - 2
src/mx2cc/errors.monkey2

@@ -7,8 +7,7 @@ Class ErrorEx Extends Throwable
 	Method New( msg:String )
 		Self.msg=msg
 		
-		Local builder:=Builder.instance
-		builder.errors.Push( Self )
+		Builder.errors.Push( Self )
 	End
 	
 	Method ToString:String() Virtual

+ 211 - 260
src/mx2cc/expr.monkey2

@@ -153,10 +153,6 @@ Class IdentExpr Extends Expr
 		Self.ident=ident
 	End
 	
-	Method ToString:String() Override
-		Return ident
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local value:=scope.FindValue( ident )
@@ -173,6 +169,11 @@ Class IdentExpr Extends Expr
 		Return type
 	End
 
+	Method ToString:String() Override
+	
+		Return ident
+	End
+	
 End
 
 Class MemberExpr Extends Expr
@@ -186,10 +187,6 @@ Class MemberExpr Extends Expr
 		Self.ident=ident
 	End
 	
-	Method ToString:String() Override
-		Return expr.ToString()+"."+ident
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local value:=expr.SemantRValue( scope )
@@ -212,6 +209,11 @@ Class MemberExpr Extends Expr
 		Return type2
 	End
 
+	Method ToString:String() Override
+
+		Return expr.ToString()+"."+ident
+	End
+	
 End
 
 Class InvokeExpr Extends Expr
@@ -225,10 +227,6 @@ Class InvokeExpr Extends Expr
 		Self.args=args
 	End
 	
-	Method ToString:String() Override
-		Return expr.ToString()+"("+Join( args )+")"
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local args:=SemantArgs( Self.args,scope )
@@ -239,70 +237,76 @@ Class InvokeExpr Extends Expr
 		
 		Return ivalue
 	End
+
+	Method ToString:String() Override
 	
+		Return expr.ToString()+"("+Join( args )+")"
+	End
 End
 
 Class GenericExpr Extends Expr
 
 	Field expr:Expr
-	Field types:TypeExpr[]
+	Field args:Expr[]
 	
-	Method New( expr:Expr,types:TypeExpr[],srcpos:Int,endpos:Int )
+	Method New( expr:Expr,args:Expr[],srcpos:Int,endpos:Int )
 		Super.New( srcpos,endpos )
 		Self.expr=expr
-		Self.types=types
-	End
-	
-	Method ToString:String() Override
-		Return expr.ToString()+"<"+Join( types )+">"
+		Self.args=args
 	End
 	
 	Method OnSemant:Value( scope:Scope ) Override
 	
-		Local types:=SemantTypes( Self.types,scope )
-		
 		Local value:=expr.Semant( scope )
 		
+		Local args:=New Type[Self.args.Length]
+
+		For Local i:=0 Until args.Length
+			args[i]=Self.args[i].SemantType( scope )
+		Next
+		
 		'FIXME: need proper 'WhereExpr's!
 		'
 		Local tvalue:=Cast<TypeValue>( value )
-		If tvalue Return New TypeValue( tvalue.ttype.GenInstance( types ) )
+		If tvalue Return New TypeValue( tvalue.ttype.GenInstance( args ) )
 		
-		Return value.GenInstance( types )
+		Return value.GenInstance( args )
 	End
-	
+
 	Method OnSemantType:Type( scope:Scope ) Override
 	
-		Local types:=SemantTypes( Self.types,scope )
-		
 		Local type:=Self.expr.SemantType( scope,True )
 		
-		Return type.GenInstance( types )
+		Local args:=New Type[Self.args.Length]
+
+		For Local i:=0 Until args.Length
+			args[i]=Self.args[i].SemantType( scope )
+		Next
+		
+		Return type.GenInstance( args )
 	End
 
+	Method ToString:String() Override
+
+		Return expr.ToString()+"<"+Join( args )+">"
+	End
 End
 
 Class NewObjectExpr Extends Expr
 
-	Field type:TypeExpr
+	Field type:Expr
 	Field args:Expr[]
 	
-	Method New( type:TypeExpr,args:Expr[],srcpos:Int,endpos:Int )
+	Method New( type:Expr,args:Expr[],srcpos:Int,endpos:Int )
 		Super.New( srcpos,endpos )
 		
 		Self.type=type
 		Self.args=args
 	End
 	
-	Method ToString:String() Override
-		Local str:="New "+type.ToString()
-		If args str+="("+Join( args )+")"
-		Return str
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
-		Local type:=Self.type.Semant( scope )
+		Local type:=Self.type.SemantType( scope )
 		
 		Local ctype:=TCast<ClassType>( type )
 		If Not ctype Throw New SemantEx( "Type '"+type.Name+"' is not a class" )
@@ -348,6 +352,13 @@ Class NewObjectExpr Extends Expr
 		
 		Return New NewObjectValue( ctype,ctorFunc,args )
 	End
+
+	Method ToString:String() Override
+		Local str:="New "+type.ToString()
+		If args str+="("+Join( args )+")"
+		Return str
+	End
+	
 End
 
 Class NewArrayExpr Extends Expr
@@ -364,14 +375,9 @@ Class NewArrayExpr Extends Expr
 		Self.inits=inits
 	End
 	
-	Method ToString:String() Override
-		If sizes Return "New "+type.type.ToString()+"["+Join( sizes )+"]"
-		Return "New "+type.ToString()+"("+Join( inits )+")"
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
-		Local atype:=TCast<ArrayType>( type.Semant( scope ) )
+		Local atype:=TCast<ArrayType>( type.SemantType( scope ) )
 		If Not atype SemantError( "NewArrayExpr.OnSemant()" )
 		
 		If atype.elemType.IsGeneric Throw New SemantEx( "Array element type '"+atype.elemType.Name+"' is generic" )
@@ -392,6 +398,13 @@ Class NewArrayExpr Extends Expr
 		Return New NewArrayValue( atype,sizes,inits )
 	End
 		
+	Method ToString:String() Override
+	
+		If sizes Return "New "+type.type.ToString()+"["+Join( sizes )+"]"
+		
+		Return "New "+type.ToString()+"("+Join( inits )+")"
+	End
+	
 End
 
 Class IndexExpr Extends Expr
@@ -405,10 +418,6 @@ Class IndexExpr Extends Expr
 		Self.args=args
 	End
 	
-	Method ToString:String() Override
-		Return expr.ToString()+"["+Join( args )+"]"
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local value:=expr.Semant( scope )
@@ -418,15 +427,19 @@ Class IndexExpr Extends Expr
 		Return value.Index( args )
 	End
 
+	Method ToString:String() Override
+	
+		Return expr.ToString()+"["+Join( args )+"]"
+	End
 End
 
 Class ExtendsExpr Extends Expr
 
 	Field op:String
 	Field expr:Expr
-	Field type:TypeExpr
+	Field type:Expr
 	
-	Method New( op:String,expr:Expr,type:TypeExpr,srcpos:Int,endpos:Int )
+	Method New( op:String,expr:Expr,type:Expr,srcpos:Int,endpos:Int )
 		Super.New( srcpos,endpos )
 		Self.op=op
 		Self.expr=expr
@@ -435,7 +448,7 @@ Class ExtendsExpr Extends Expr
 	
 	Method OnSemant:Value( scope:Scope ) Override
 	
-		Local ctype:=TCast<ClassType>( Self.type.Semant( scope ) )
+		Local ctype:=TCast<ClassType>( Self.type.SemantType( scope ) )
 		If Not ctype Or (ctype.cdecl.kind<>"class" And ctype.cdecl.kind<>"interface" And ctype.cdecl.kind<>"protocol" ) 
 			Throw New SemantEx( "Type '"+type.ToString()+"' is not a class or interface type" )
 		Endif
@@ -461,37 +474,37 @@ Class ExtendsExpr Extends Expr
 	
 	Method OnSemantWhere:Bool( scope:Scope ) Override
 	
-		Local ctype:=TCast<ClassType>( Self.type.Semant( scope ) )
+		Local ctype:=TCast<ClassType>( Self.type.SemantType( scope ) )
 		
 		If Not ctype Or (ctype.cdecl.kind<>"class" And ctype.cdecl.kind<>"interface" And ctype.cdecl.kind<>"protocol" ) 
 			Throw New SemantEx( "Type '"+type.ToString()+"' is not a class or interface type" )
-		endif
+		Endif
 		
 		Local type:=Self.expr.SemantType( scope )
 
 		Return type.ExtendsType( ctype )
 	End
-
+	
+	Method ToString:String() Override
+	
+		Return expr.ToString()+" "+op.Capitalize()+" "+type.ToString()
+	End
 End
 
 Class CastExpr Extends Expr
 
-	Field type:TypeExpr
+	Field type:Expr
 	Field expr:Expr
 	
-	Method New( type:TypeExpr,expr:Expr,srcpos:Int,endpos:Int )
+	Method New( type:Expr,expr:Expr,srcpos:Int,endpos:Int )
 		Super.New( srcpos,endpos )
 		Self.type=type
 		Self.expr=expr
 	End
 	
-	Method ToString:String() Override
-		Return "cast<"+type.ToString()+">("+expr.ToString()+")"
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
-		Local type:=Self.type.Semant( scope )
+		Local type:=Self.type.SemantType( scope )
 		
 		Local value:=Self.expr.Semant( scope )
 		
@@ -512,6 +525,11 @@ Class CastExpr Extends Expr
 		Return New ExplicitCastValue( type,value )
 	End
 		
+	Method ToString:String() Override
+	
+		Return "Cast<"+type.ToString()+">("+expr.ToString()+")"
+	End
+	
 End
 
 Class SelfExpr Extends Expr
@@ -520,10 +538,6 @@ Class SelfExpr Extends Expr
 		Super.New( srcpos,endpos )
 	End
 	
-	Method ToString:String() Override
-		Return "self"
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 		
 		Local block:=Cast<Block>( scope )
@@ -533,6 +547,11 @@ Class SelfExpr Extends Expr
 		Return Null
 	End
 	
+	Method ToString:String() Override
+	
+		Return "Self"
+	End
+	
 End
 
 Class SuperExpr Extends Expr
@@ -541,10 +560,6 @@ Class SuperExpr Extends Expr
 		Super.New( srcpos,endpos )
 	End
 	
-	Method ToString:String() Override
-		Return "super"
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local block:=Cast<Block>( scope )
@@ -565,6 +580,10 @@ Class SuperExpr Extends Expr
 		Return Null
 	End
 	
+	Method ToString:String() Override
+		Return "Super"
+	End
+	
 End
 
 Class NullExpr Extends Expr
@@ -573,14 +592,14 @@ Class NullExpr Extends Expr
 		Super.New( srcpos,endpos )
 	End
 	
-	Method ToString:String() Override
-		Return "null"
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 		Return New NullValue
 	End
 	
+	Method ToString:String() Override
+		Return "Null"
+	End
+	
 End
 
 Class UnaryopExpr Extends Expr
@@ -594,10 +613,6 @@ Class UnaryopExpr Extends Expr
 		Self.expr=expr
 	End
 	
-	Method ToString:String() Override
-		Return op+expr.ToString()
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local value:=expr.SemantRValue( scope )
@@ -633,6 +648,10 @@ Class UnaryopExpr Extends Expr
 		Return EvalUnaryop( type,op,value.UpCast( type ) )
 	End
 	
+	Method ToString:String() Override
+		Return op.Capitalize()+expr.ToString()
+	End
+	
 End
 
 Class BinaryopExpr Extends Expr
@@ -647,67 +666,7 @@ Class BinaryopExpr Extends Expr
 		Self.lhs=lhs
 		Self.rhs=rhs
 	End
-	
-	Method ToString:String() Override
-		Return "("+lhs.ToString()+op+rhs.ToString()+")"
-	End
-	
-	Function BalanceIntegralTypes:Type( lhs:PrimType,rhs:PrimType )
-	
-		If Not lhs Or Not rhs Or Not lhs.IsIntegral Or Not rhs.IsIntegral
-			Throw New SemantEx( "Types must be integral" )
-		Endif
-
-		'Think about this more...!
-		'
-		If lhs=Type.ULongType Or rhs=Type.ULongType Return Type.ULongType
-		
-		If lhs=Type.LongType Or rhs=Type.LongType Return Type.LongType
-		
-		If lhs.IsUnsignedIntegral Or rhs.IsUnsignedIntegral Return Type.UIntType
-		
-		Return Type.IntType
-	End
-	
-	function BalanceNumericTypes:Type( lhs:PrimType,rhs:PrimType )
-
-		If Not lhs Or Not rhs Or Not lhs.IsNumeric Or Not rhs.IsNumeric
-			Throw New SemantEx( "Types must be numeric" )
-		Endif
-	
-		If lhs=Type.DoubleType Or rhs=Type.DoubleType Return Type.DoubleType
 
-		If lhs=Type.FloatType Or rhs=Type.FloatType Return Type.FloatType
-		
-		Return BalanceIntegralTypes( lhs,rhs )
-	End
-	
-	function BalancePrimTypes:Type( lhs:PrimType,rhs:PrimType )
-	
-		If Not lhs Or Not rhs
-			Throw New SemantEx( "Types must be primitive" )
-		Endif
-	
-		If lhs=Type.StringType Or rhs=Type.StringType Return Type.StringType
-		
-		Return BalanceNumericTypes( lhs,rhs )
-	End
-	
-	Function BalanceTypes:Type( lhs:Type,rhs:Type )
-	
-		Local plhs:=TCast<PrimType>( lhs )
-		Local prhs:=TCast<PrimType>( rhs )
-		
-		If plhs And prhs Return BalancePrimTypes( plhs,prhs )
-		
-		If lhs.DistanceToType( rhs )>=0 Return rhs		'And rhs.DistanceToType( lhs )<=0 Return rhs
-		If rhs.DistanceToType( lhs )>=0 Return lhs		'And lhs.DistanceToType( rhs )<=0 Return lhs
-		
-		Throw New SemantEx( "Types '"+lhs.Name+"' and '"+rhs.Name+"' are incompatible" )
-		
-		Return Null
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local lhs:=Self.lhs.Semant( scope )
@@ -724,115 +683,30 @@ Class BinaryopExpr Extends Expr
 			rhs=rhs.ToRValue()
 		Endif
 		
-		'check for overloaded operator
+		'check for overloadeded operator
 		'
 		Local node:=lhs.FindValue( op )
 		If node 
-			Local args:=New Value[1]
-			args[0]=rhs
-			Return node.Invoke( args )
-		Endif
-
-		'handle pointer arithmetic
-		'
-		Local lptype:=TCast<PointerType>( lhs.type )
-		Local rptype:=TCast<PointerType>( rhs.type )
-		If lptype Or rptype
-			If lptype And (op="+" Or op="-")	
-				'pointer=pointer +/- int
-				Return New BinaryopValue( lptype,op,lhs,rhs.UpCast( Type.IntType ) )
-			Else If rptype And op="+"
-				'pointer=int + pointer
-				Return New BinaryopValue( rptype,op,rhs,lhs.UpCast( Type.IntType ) )
-			Endif
-			Throw New SemantEx( "Pointer arithmetic error" )
+			Return node.Invoke( New Value[]( rhs ) )
 		Endif
 		
-		Local plhs:=TCast<PrimType>( lhs.type )
-		Local prhs:=TCast<PrimType>( rhs.type )
-		
-		Local type:Type,lhsType:Type,rhsType:Type
-		
+		'check for overloaded <=> for comparisons
+		'
 		Select op
-		Case "+"
-		
-			type=BalancePrimTypes( plhs,prhs )
-			
-		Case "*","/","mod","-"
-		
-			type=BalanceNumericTypes( plhs,prhs )
-			
-		Case "&","|","~"
-		
-			Local elhs:=TCast<EnumType>( lhs.type )
-			Local erhs:=TCast<EnumType>( rhs.type )
-			If elhs Or erhs
-				If elhs.Equals( erhs ) type=elhs
-			Else
-				type=BalanceIntegralTypes( plhs,prhs )
-			Endif
-			
-		Case "shl","shr"
-
-			type=BalanceIntegralTypes( plhs,plhs )
-			rhsType=Type.IntType
-			
 		Case "=","<>","<",">","<=",">="
-
 			Local node:=lhs.FindValue( "<=>" )
 			If node
-			
-				Local args:=New Value[1]
-				args[0]=rhs
-				lhs=node.Invoke( args )
-
-				lhsType=lhs.type
-				rhsType=lhsType
-				
-				Local ptype:=TCast<PrimType>( lhsType )
-				Assert( ptype And ptype.IsNumeric )
-				
-				rhs=New LiteralValue( rhsType,"" )
-				type=Type.BoolType
-				
-			Else If plhs=Type.BoolType Or prhs=Type.BoolType
-			
-				If op<>"=" And op<>"<>" Throw New SemantEx( "Bool values can only be compared for equality" )
-				
-				type=Type.BoolType
-			
-			Else
-			
-				type=BalanceTypes( lhs.type,rhs.type )
-				If type
-					lhsType=type
-					rhsType=type
-					type=Type.BoolType
-				Endif
-				
-			
+				lhs=node.Invoke( New Value[]( rhs ) )
+				rhs=New LiteralValue( lhs.type,"" )	'compare with '0'.
 			Endif
-			
-		Case "<=>"
-		
-			type=BalanceTypes( lhs.type,rhs.type )
-			If type
-				lhsType=type
-				rhsType=type
-				type=Type.IntType
-			Endif
-			
-		Case "and","or"
-
-			type=Type.BoolType
 		End
 		
-		If Not type Throw New SemantEx( "Parameter types for binary operator '"+op+"' cannot be determined" )
+		Local argTypes:=New Type[2]
+		Local type:=BalanceBinaryopTypes( op,lhs.type,rhs.type,argTypes )
 		
-		If Not lhsType lhsType=type
-		If Not rhsType rhsType=type
+		If Not type Throw New SemantEx( "Parameter types for binary operator '"+op+"' cannot be determined" )
 		
-		Return EvalBinaryop( type,op,lhs.UpCast( lhsType ),rhs.UpCast( rhsType ) )
+		Return EvalBinaryop( type,op,lhs.UpCast( argTypes[0] ),rhs.UpCast( argTypes[1] ) )
 	End
 	
 	Method OnSemantWhere:Bool( scope:Scope ) Override
@@ -847,6 +721,10 @@ Class BinaryopExpr Extends Expr
 		Return Not lhs.Equals( rhs )
 	End
 	
+	Method ToString:String() Override
+
+		Return "("+lhs.ToString()+op+rhs.ToString()+")"
+	End
 End
 
 Class IfThenElseExpr Extends Expr
@@ -865,15 +743,28 @@ Class IfThenElseExpr Extends Expr
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local value:=expr.SemantRValue( scope,Type.BoolType )
-		Local thenValue:=thenExpr.SemantRValue( scope )
-		Local elseValue:=elseExpr.SemantRValue( scope )
 		
-		Local type:=BinaryopExpr.BalanceTypes( thenValue.type,elseValue.type )
+		Local thenValue:=thenExpr.Semant( scope )
+		Local elseValue:=elseExpr.Semant( scope )
+
+		If thenValue.type=Type.NullType
+			elseValue=elseValue.ToRValue()
+			thenValue=thenValue.UpCast( elseValue.type )
+		Else If elseValue.type=Type.NullType
+			thenValue=thenValue.ToRValue()
+			elseValue=elseValue.UpCast( thenValue.type )
+		Endif
+		
+		Local type:=BalanceTypes( thenValue.type,elseValue.type )
 		thenValue=thenValue.UpCast( type )
 		elseValue=elseValue.UpCast( type )
 		
 		Return New IfThenElseValue( type,value,thenValue,elseValue )
 	End
+	
+	Method ToString:String() Override
+		Return "("+expr.ToString()+" ? "+thenExpr.ToString()+" Else "+elseExpr.ToString()+")"
+	End
 End
 
 Class VarptrExpr Extends Expr
@@ -885,10 +776,6 @@ Class VarptrExpr Extends Expr
 		Self.expr=expr
 	End
 	
-	Method ToString:String() Override
-		Return "Varptr "+expr.ToString()
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local value:=expr.Semant( scope )
@@ -897,32 +784,33 @@ Class VarptrExpr Extends Expr
 		
 		Return New PointerValue( value )
 	End
+
+	Method ToString:String() Override
+		Return "Varptr "+expr.ToString()
+	End
+	
 End
 
 Class LiteralExpr Extends Expr
 
 	Field toke:String
 	Field tokeType:Int
-	Field typeExpr:TypeExpr
+	Field typeExpr:Expr
 	
-	Method New( toke:String,tokeType:Int,typeExpr:TypeExpr,srcpos:Int,endpos:Int )
+	Method New( toke:String,tokeType:Int,typeExpr:Expr,srcpos:Int,endpos:Int )
 		Super.New( srcpos,endpos )
 		Self.toke=toke
 		Self.tokeType=tokeType
 		Self.typeExpr=typeExpr
 	End
 	
-	Method ToString:String() Override
-		Return toke
-	End
-	
 	Method OnSemant:Value( scope:Scope ) Override
 	
 		Local type:Type
 		
 		If typeExpr
 		 
-			type=typeExpr.Semant( scope )
+			type=typeExpr.SemantType( scope )
 
 			Local ptype:=TCast<PrimType>( type )
 			If Not ptype Throw New SemantEx( "Literal type must be a primitive type" )
@@ -982,44 +870,107 @@ Class LiteralExpr Extends Expr
 		
 		Return New LiteralValue( type,t )
 	End
+	
+	Method ToString:String() Override
+		Return toke
+	End
+	
 End
 
-Class ArrayLiteralExpr Extends Expr
+Class LambdaExpr Extends Expr
 
-	Field exprs:Expr[]
+	Field decl:FuncDecl
 
-	Method New( exprs:Expr[],srcpos:Int,endpos:Int )
+	Method New( decl:FuncDecl,srcpos:Int,endpos:Int )
 		Super.New( srcpos,endpos )
+		Self.decl=decl
+	End
+	
+	Method OnSemant:Value( scope:Scope ) Override
+	
+		Local func:=New FuncValue( decl,scope,Null,Null )
 		
-		Self.exprs=exprs
+		func.Semant()
+		
+		Return func
 	End
 
 	Method ToString:String() Override
-		Return "["+Join( exprs )+"]"
+		Return decl.ToString()
+	End
+End
+
+Class ArrayTypeExpr Extends Expr
+
+	Field type:Expr
+	Field rank:Int
+	
+	Method New( type:Expr,rank:Int,srcpos:Int,endpos:Int )
+		Super.New( srcpos,endpos )
+		Self.type=type
+		Self.rank=rank
+	End
+	
+	Method OnSemantType:Type( scope:Scope ) Override
+	
+		Local type:=Self.type.SemantType( scope )
+		
+		Return New ArrayType( type,rank )
 	End
 
+	Method ToString:String() Override
+		Return type.ToString()+"[,,,,,,,,,,,".Slice( 0,rank )+"]"
+	End
+	
 End
 
-Class LambdaExpr Extends Expr
+Class FuncTypeExpr Extends Expr
 
-	Field decl:FuncDecl
+	Field retType:Expr
+	Field params:VarDecl[]
 
-	Method New( decl:FuncDecl,srcpos:Int,endpos:Int )
+	Method New( retType:Expr,params:VarDecl[],srcpos:Int,endpos:Int )
 		Super.New( srcpos,endpos )
-		Self.decl=decl
+		Self.retType=retType
+		Self.params=params
+	End
+
+	Method OnSemantType:Type( scope:Scope ) Override
+
+		Local retType:=Self.retType.SemantType( scope )
+		
+		Local argTypes:=New Type[params.Length]
+		For Local i:=0 Until argTypes.Length
+			argTypes[i]=params[i].type.SemantType( scope )
+		Next
+		
+		Return New FuncType( retType,argTypes )
 	End
 	
 	Method ToString:String() Override
-		Return decl.ToString()
+		Return retType.ToString()+"("+Join( params )+")"
 	End
+
+End
+
+Class PointerTypeExpr Extends Expr
+
+	Field type:Expr
 	
-	Method OnSemant:Value( scope:Scope ) Override
-	
-		Local func:=New FuncValue( decl,scope,Null,Null )
-		
-		func.Semant()
+	Method New( type:Expr,srcpos:Int,endpos:Int )
+		Super.New( srcpos,endpos )
 		
-		Return func
+		Self.type=type
 	End
 	
+	Method OnSemantType:Type( scope:Scope ) Override
+	
+		Local type:=Self.type.SemantType( scope )
+		
+		Return New PointerType( type )
+	End
+
+	Method ToString:String() Override
+		Return type.ToString()+" Ptr"
+	End
 End

+ 181 - 0
src/mx2cc/filescope.monkey2

@@ -0,0 +1,181 @@
+
+Namespace mx2
+
+Class FileScope Extends Scope
+
+	Field fdecl:FileDecl
+	
+	Field nmspace:NamespaceScope
+	
+	Field usings:Stack<NamespaceScope>
+	
+	Field toSemant:=New Stack<SNode>
+
+'	Field classexts:=New Stack<ClassType>
+	
+	Method New( fdecl:FileDecl )
+		Super.New( Null )
+		
+		Local module:=fdecl.module
+
+		Self.fdecl=fdecl
+		Self.usings=module.usings
+		
+		nmspace=Builder.GetNamespace( fdecl.nmspace )
+		nmspace.inner.Push( Self )
+		outer=nmspace
+		
+		For Local member:=Eachin fdecl.members
+
+			Local node:=member.ToNode( Self )
+			
+			If member.IsExtension
+			
+				nmspace.classexts.Push( TCast<ClassType>( node ) )
+				
+			Else If member.IsPublic
+			
+				If Not nmspace.Insert( member.ident,node ) Continue
+				
+			Else
+			
+				If Not Insert( member.ident,node ) Continue
+				
+			Endif
+
+			toSemant.Push( node )
+		Next
+	End
+	
+	Method UsingNamespace:Bool( nmspace:NamespaceScope )
+		If usings.Contains( nmspace ) Return True
+		usings.Push( nmspace )
+		Return False
+	End
+		
+	Method UsingInner( nmspace:NamespaceScope )
+		For Local scope:=Eachin nmspace.inner
+			Local nmspace:=Cast<NamespaceScope>( scope )
+			If nmspace UsingNamespace( nmspace )
+		Next
+	End
+	
+	Method UsingAll( nmspace:NamespaceScope )
+		If UsingNamespace( nmspace ) Return
+		For Local scope:=Eachin nmspace.inner
+			Local nmspace:=Cast<NamespaceScope>( scope )
+			If nmspace UsingAll( nmspace )
+		Next
+	End
+	
+	Method Semant()
+	
+'		Print "Semating:"+fdecl.path
+
+		If nmspace<>Builder.monkeyNamespace
+			UsingAll( Builder.monkeyNamespace )
+		Endif
+
+		For Local use:=Eachin fdecl.usings
+		
+			If use="*"
+				UsingAll( Builder.rootNamespace )
+				Continue
+			Endif
+		
+			If use.EndsWith( ".." )
+				Local nmspace:=Builder.GetNamespace( use.Slice( 0,-2 ) )
+				UsingAll( nmspace )
+				Continue
+			Endif
+		
+			If use.EndsWith( ".*" )
+				Local nmspace:=Builder.GetNamespace( use.Slice( 0,-2 ) )
+				UsingInner( nmspace )
+				Continue
+			Endif
+			
+			Local nmspace:=Builder.GetNamespace( use )
+			If nmspace UsingNamespace( nmspace )
+		Next
+	
+		For Local node:=Eachin toSemant
+			Try			
+				node.Semant()
+			Catch ex:SemantEx
+			End
+		Next
+		
+	End
+	
+	Method FindInUsings:SNode( ident:String,istype:Bool )
+
+		Local finder:=New NodeFinder( ident,istype )
+		
+		For Local nmspace:=Eachin usings
+			finder.Find( nmspace )
+		Next
+		
+		Return finder.Found
+	End
+	
+	Method FindNode:SNode( ident:String ) Override
+	
+		Local node:=Super.FindNode( ident )
+		If node Return node
+		
+		Return FindInUsings( ident,False )
+	End
+	
+	Method FindType:Type( ident:String ) Override
+	
+		Local type:=Super.FindType( ident )
+		If type Return type
+		
+		Return Cast<Type>( FindInUsings( ident,True ) )
+	End
+	
+	Function FindExtension( finder:NodeFinder,nmspace:NamespaceScope,ctype:ClassType )
+
+		Local exts:=nmspace.FindClassExtensions( ctype )
+		If Not exts Return
+			
+		For Local ext:=Eachin exts
+			finder.Find( ext.scope )
+		Next
+	End
+	
+	Function FindExtension:SNode( ident:String,istype:Bool,ctype:ClassType )
+	
+		Local scope:=Scope.Semanting()
+		If Not scope Return Null
+		
+		Local fscope:=scope.FindFile()
+		If Not fscope Return Null
+		
+		Local finder:=New NodeFinder( ident,istype )
+		
+		'search hierarchy
+		Local nmspace:=fscope.nmspace
+		While nmspace
+			FindExtension( finder,nmspace,ctype )
+'			If finder.Found Return finder.Found
+			nmspace=Cast<NamespaceScope>( nmspace.outer )
+		Wend
+		If finder.Found Return finder.Found
+
+		'search usings
+		For Local nmspace:=Eachin fscope.usings
+			FindExtension( finder,nmspace,ctype )
+		Next
+		If finder.Found Return finder.Found
+		
+		Return Null
+	End
+
+	Method FindFile:FileScope() Override
+
+		Return Self
+	End
+	
+End

+ 62 - 20
src/mx2cc/func.monkey2

@@ -11,18 +11,6 @@ Class FuncDecl Extends Decl
 	
 	Field stmts:StmtExpr[]
 	
-	Method ToString:String() Override
-		Local str:=Super.ToString()
-		If genArgs str+="<"+",".Join( genArgs )+">"
-		Return str+":"+type.ToString()
-	End
-	
-	Method Emit( buf:StringStack,spc:String ) Override
-		buf.Push( spc+ToString() )
-		EmitStmts( stmts,buf,spc )
-		buf.Push( spc+"End" )
-	End
-	
 	Method ToNode:SNode( scope:Scope ) Override
 	
 		Local types:=New Type[genArgs.Length]
@@ -33,6 +21,12 @@ Class FuncDecl Extends Decl
 		Return New FuncValue( Self,scope,types,Null )
 	End
 
+	Method ToString:String() Override
+		Local str:=Super.ToString()
+		If genArgs str+="<"+",".Join( genArgs )+">"
+		Return str+":"+type.ToString()
+	End
+	
 End
 
 '***** FuncValue *****
@@ -53,6 +47,8 @@ Class FuncValue Extends Value
 	Field overrides:FuncValue
 	
 	Field params:VarValue[]
+	
+	Field selfType:ClassType
 	Field selfValue:Value
 	
 	Field instances:Stack<FuncValue>
@@ -168,9 +164,44 @@ Class FuncValue Extends Value
 
 		'Semant func type
 		'
-		type=fdecl.type.Semant( block )
+		type=fdecl.type.SemantType( block )
 		ftype=TCast<FuncType>( type )
 		
+		'Semant selfType and selfValue
+		'
+		If IsCtor Or IsMethod
+	
+			If IsExtension
+			
+				selfType=cscope.ctype
+				
+				If selfType.cdecl.IsExtension selfType=selfType.superType
+				
+'				If fdecl.IsExtension selfType=selfType.superType
+			
+				selfValue=New VarValue( "capture","self",New LiteralValue( selfType,"" ),scope )
+				
+			Else
+			
+				selfType=cscope.ctype
+			
+				selfValue=New SelfValue( selfType )
+				
+			Endif
+			
+		Else If IsLambda
+		
+			selfValue=Cast<Block>( scope ).func.selfValue
+			
+			If selfValue
+			
+				selfValue=New VarValue( "capture","self",selfValue,block )
+				
+				captures.Push( Cast<VarValue>( selfValue ) )
+			Endif
+		
+		Endif
+		
 		'That's it for generic funcs
 		'
 		If block.IsGeneric 
@@ -275,7 +306,7 @@ Class FuncValue Extends Value
 		If used Return
 		used=True
 
-		Builder.instance.semantStmts.Push( Self )
+		Builder.semantStmts.Push( Self )
 	End
 	
 	Method ToValue:Value( instance:Value ) Override
@@ -290,7 +321,7 @@ Class FuncValue Extends Value
 		
 			If Not instance Throw New SemantEx( "Method '"+ToString()+"' cannot be accessed without an instance" )
 			
-			If Not instance.type.ExtendsType( cscope.ctype )
+			If Not instance.type.ExtendsType( selfValue.type )'cscope.ctype )
 				Throw New SemantEx( "Method '"+ToString()+"' cannot be accessed from an instance of a different class" )
 			Endif
 			
@@ -346,11 +377,17 @@ Class FuncValue Extends Value
 			End
 		Next
 		
+		#rem
+		
 		If IsCtor Or IsMethod
 	
 			If IsExtension
-	
-				selfValue=New VarValue( "capture","self",New LiteralValue( cscope.ctype,"" ),scope )
+			
+				Local ctype:=cscope.ctype
+				
+				If fdecl.IsExtension ctype=ctype.superType
+			
+				selfValue=New VarValue( "capture","self",New LiteralValue( ctype,"" ),scope )
 				
 			Else
 			
@@ -361,12 +398,18 @@ Class FuncValue Extends Value
 		Else If IsLambda
 		
 			selfValue=Cast<Block>( scope ).func.selfValue
+			
 			If selfValue
+			
 				selfValue=New VarValue( "capture","self",selfValue,block )
+				
 				captures.Push( Cast<VarValue>( selfValue ) )
 			Endif
 		
 		Endif
+		
+		#end
+		
 	End
 	
 	Method SemantInvokeNew()
@@ -418,8 +461,7 @@ Class FuncValue Extends Value
 			Endif
 			
 			If instanceOf
-				Local builder:=Builder.instance
-				Local module:=builder.semantingModule
+				Local module:=Builder.semantingModule
 				module.genInstances.Push( Self )
 			Endif
 
@@ -678,7 +720,7 @@ Class FuncList Extends SNode
 				Local func:=Cast<FuncValue>( tfunc.Semant() )
 				If Not func Continue
 				
-				If Not func.block.IsGeneric
+				If ident<>"to" And Not func.block.IsGeneric
 					Local func2:=FindFunc( func.ftype.argTypes )
 					If func2 Throw New SemantEx( "Duplicate declaration '"+func.ToString()+"'",tfunc.pnode )
 				Endif

+ 7 - 2
src/mx2cc/mung.monkey2

@@ -183,6 +183,9 @@ Function ClassName:String( ctype:ClassType )
 	
 		Return symbol
 	Endif
+	
+	If ctype.cdecl.IsExtension Return "x_"+ScopeName( ctype.scope )
+
 
 	Return "t_"+ScopeName( ctype.scope )
 End
@@ -207,9 +210,11 @@ Function FuncName:String( func:FuncValue )
 		Return symbol
 	Endif
 	
-	If fdecl.kind="function" Or func.types
-
+	If fdecl.kind="function" Or func.IsExtension'types
+	
 		Local sym:="g_"+ScopeName( func.scope )+"_"+MungIdent( fdecl.ident )
+		
+		If fdecl.ident="to" sym+="_"+MungArg( func.ftype.retType )
 
 '		hopefully not necessary!		
 		If func.types sym+=MungArgs( func.types )

+ 36 - 34
src/mx2cc/mx2.monkey2

@@ -1,39 +1,41 @@
 
 Namespace mx2
 
-#Import "util.monkey2"
-
-#Import "scope.monkey2"
-#Import "value.monkey2"
-#Import "type.monkey2"
-#Import "node.monkey2"
-#Import "stmt.monkey2"
-
-#Import "errors.monkey2"
-#Import "toker.monkey2"
-#Import "parser.monkey2"
-#Import "decl.monkey2"
-#Import "expr.monkey2"
-#Import "eval.monkey2"
-#Import "typeexpr.monkey2"
-#Import "stmtexpr.monkey2"
-#Import "class.monkey2"
-#Import "func.monkey2"
-#Import "var.monkey2"
-#Import "enum.monkey2"
-#Import "property.monkey2"
-#Import "alias.monkey2"
-#Import "namespace.monkey2"
-#Import "overload.monkey2"
-#Import "balance.monkey2"
-#Import "module.monkey2"
-
-#Import "translator.monkey2"
-#Import "translator_cpp.monkey2"
-#Import "mung.monkey2"
-
-#Import "builder.monkey2"
-#Import "buildproduct.monkey2"
+#Import "util"
+
+#Import "scope"
+#Import "value"
+#Import "type"
+#Import "node"
+#Import "stmt"
+#Import "filescope"
+#Import "block"
+
+#Import "errors"
+#Import "toker"
+#Import "parser"
+#Import "decl"
+#Import "expr"
+#Import "eval"
+#Import "stmtexpr"
+#Import "class"
+#Import "func"
+#Import "var"
+#Import "enum"
+#Import "property"
+#Import "alias"
+#Import "namespace"
+#Import "overload"
+#Import "balance"
+#Import "module"
+#Import "nodefinder"
+
+#Import "translator"
+#Import "translator_cpp"
+#Import "mung"
+
+#Import "builder"
+#Import "buildproduct"
 
 Using std
 Using std.stringio
@@ -49,4 +51,4 @@ Using lib.c
 ' 3) edit .sh and .bat files to use new version (common.sh, common.bat)
 ' 4) ./rebuildall
 '
-Const MX2CC_VERSION:="1.0.4"
+Const MX2CC_VERSION:="1.0.5"

+ 55 - 42
src/mx2cc/mx2cc.monkey2

@@ -3,15 +3,15 @@ Namespace mx2cc
 
 Using mx2.docs
 
-#Import "<hoedown>"
 #Import "<std>"
 
-#Import "mx2.monkey2"
+#Import "mx2"
 
-#Import "docs/docsmaker.monkey2"
-#Import "docs/jsonbuffer.monkey2"
-#Import "docs/markdownbuffer.monkey2"
-#Import "docs/manpage.monkey2"
+#Import "docs/docsmaker"
+#Import "docs/jsonbuffer"
+#Import "docs/minimarkdown"
+#Import "docs/markdownbuffer"
+#Import "docs/manpage"
 
 Using libc..
 Using std..
@@ -19,19 +19,16 @@ Using mx2..
 
 Global StartDir:String
 
-Const TestArgs:="mx2cc makemods -clean"	' -target=android"
+'Const TestArgs:="mx2cc makedocs mojo"
 
-'Const TestArgs:="mx2cc makeapp -clean -target=android src/mx2cc/test.monkey2"
+Const TestArgs:="mx2cc makeapp -clean -config=debug -target=desktop -product=D:/test_app/test.exe -assets=D:/test_app/assets -dlls=D:/test_app/ src/mx2cc/test.monkey2"
+'Const TestArgs:="mx2cc makeapp -clean -config=debug -target=desktop src/mx2cc/test.monkey2"
 
-'Const TestArgs:="mx2cc makeapp -clean -target=android bananas/gridshooter/gridshooter.monkey2"
-
-'Const TestArgs:="mx2cc makemods -clean std"' -target=android"
-
-'Const TestArgs:="mx2cc makeapp src/ted2/ted2.monkey2"
+'Const TestArgs:="mx2cc makeapp -clean src/ted2/ted2"
 
 'Const TestArgs:="mx2cc makemods -clean -config=release monkey libc miniz stb-image hoedown std"
 
-'Const TestArgs:="mx2cc makeapp -verbose -target=desktop -config=release src/mx2cc/mx2cc.monkey2"
+'Const TestArgs:="mx2cc makeapp -verbose -target=desktop -config=release src/mx2cc/mx2cc"
 
 Function Main()
 
@@ -63,6 +60,7 @@ Function Main()
 		exit_(0)
 #Endif
 		args=TestArgs.Split( " " )
+		If args.Length<2 exit_(0)
 		
 	Endif
 	
@@ -120,28 +118,28 @@ Function MakeApp:Bool( args:String[] )
 	Print "***** Building app '"+opts.mainSource+"' *****"
 	Print ""
 
-	Local builder:=New Builder( opts )
+	New BuilderInstance( opts )
 	
-	builder.Parse()
-	If builder.errors.Length Return False
+	Builder.Parse()
+	If Builder.errors.Length Return False
 	If opts.passes=1 Return True
 	
-	builder.Semant()
-	If builder.errors.Length Return False
+	Builder.Semant()
+	If Builder.errors.Length Return False
 	If opts.passes=2 Return True
 	
-	builder.Translate()
-	If builder.errors.Length Return False
+	Builder.Translate()
+	If Builder.errors.Length Return False
 	If opts.passes=3 Return True
 	
-	builder.product.Build()
-	If builder.errors.Length Return False
+	Builder.product.Build()
+	If Builder.errors.Length Return False
 	If opts.passes=4
-		Print "Application built:"+builder.product.outputFile
+		Print "Application built:"+Builder.product.outputFile
 		Return True
 	Endif
 	
-	builder.product.Run()
+	Builder.product.Run()
 	Return True
 End
 
@@ -162,9 +160,12 @@ Function MakeMods:Bool( args:String[] )
 	
 	Local errs:=0
 	
+	Local target:=opts.target
+	
 	For Local modid:=Eachin args
 	
 		Local path:="modules/"+modid+"/"+modid+".monkey2"
+		
 		If GetFileType( path )<>FILETYPE_FILE Fail( "Module file '"+path+"' not found" )
 	
 		Print ""
@@ -172,23 +173,24 @@ Function MakeMods:Bool( args:String[] )
 		Print ""
 		
 		opts.mainSource=RealPath( path )
+		opts.target=target
 		
-		Local builder:=New Builder( opts )
+		New BuilderInstance( opts )
 		
-		builder.Parse()
-		If builder.errors.Length errs+=1;Continue
+		Builder.Parse()
+		If Builder.errors.Length errs+=1;Continue
 		If opts.passes=1 Continue
 
-		builder.Semant()
-		If builder.errors.Length errs+=1;Continue
+		Builder.Semant()
+		If Builder.errors.Length errs+=1;Continue
 		If opts.passes=2 Continue
 		
-		builder.Translate()
-		If builder.errors.Length errs+=1;Continue
+		Builder.Translate()
+		If Builder.errors.Length errs+=1;Continue
 		If opts.passes=3 Continue
 		
-		builder.product.Build()
-		If builder.errors.Length errs+=1;Continue
+		Builder.product.Build()
+		If Builder.errors.Length errs+=1;Continue
 	Next
 	
 	Return errs=0
@@ -226,15 +228,15 @@ Function MakeDocs:Bool( args:String[] )
 		
 		opts.mainSource=RealPath( path )
 		
-		Local builder:=New Builder( opts )
+		New BuilderInstance( opts )
 
-		builder.Parse()
-		If builder.errors.Length errs+=1;Continue
+		Builder.Parse()
+		If Builder.errors.Length errs+=1;Continue
 		
-		builder.Semant()
-		If builder.errors.Length errs+=1;Continue
+		Builder.Semant()
+		If Builder.errors.Length errs+=1;Continue
 		
-		docsMaker.MakeDocs( builder.modules.Top )
+		docsMaker.MakeDocs( Builder.modules.Top )
 	Next
 	
 	Local api_indices:=New StringStack
@@ -292,9 +294,20 @@ Function ParseOpts:String[]( opts:BuildOpts,args:String[] )
 			Continue
 		Endif
 		
-		Local opt:=arg.Slice( 0,j ),val:=arg.Slice( j+1 ).ToLower()
+		Local opt:=arg.Slice( 0,j ),val:=arg.Slice( j+1 )
+		
+		Local path:=val.Replace( "\","/" )
+		If path.StartsWith( "~q" ) And path.EndsWith( "~q" ) path=path.Slice( 1,-1 )
+		
+		val=val.ToLower()
 		
 		Select opt
+		Case "-product"
+			opts.product=path
+		Case "-assets"
+			opts.assets=path
+		Case "-dlls"
+			opts.dlls=path
 		Case "-apptype"
 			Select val
 			Case "gui","console"
@@ -304,7 +317,7 @@ Function ParseOpts:String[]( opts:BuildOpts,args:String[] )
 			End
 		Case "-target"
 			Select val
-			Case "desktop","emscripten","android","ios"
+			Case "desktop","windows","macos","linux","emscripten","android","ios"
 				opts.target=val
 			Default
 				Fail( "Invalid value for 'target' option: '"+val+"' - must be 'desktop', 'emscripten', 'android' or 'ios'" )

+ 24 - 0
src/mx2cc/namespace.monkey2

@@ -45,6 +45,7 @@ End
 Class NamespaceScope Extends Scope
 
 	Field ntype:NamespaceType
+	Field classexts:=New Stack<ClassType>
 	
 	Method New( ntype:NamespaceType,outer:NamespaceScope )
 		Super.New( outer )
@@ -89,5 +90,28 @@ Class NamespaceScope Extends Scope
 		
 		Return Self
 	End
+	
+	Method FindClassExtensions:Stack<ClassType>( ctype:ClassType )
+	
+		Local exts:Stack<ClassType>
+		
+		For Local ext:=Eachin classexts
+		
+			If ext.IsGeneric
+				If ctype.instanceOf
+					If ext.superType.instanceOf.ExtendsType( ctype.instanceOf )
+						ext=TCast<ClassType>( ext.GenInstance( ctype.types ) )
+					Endif
+				Endif
+			Endif
+
+			If Not ext.superType.ExtendsType( ctype ) Continue
+			
+			If Not exts exts=New Stack<ClassType>
+			exts.Push( ext )
+		Next
+		
+		Return exts
+	End
 
 End

+ 34 - 15
src/mx2cc/node.monkey2

@@ -3,7 +3,24 @@ Namespace mx2
 
 Const DEBUG_SEMANTS:=False'True
 
-Class PNode
+Class UNode
+
+	Method ToString:String() Virtual
+		Return "?????"
+	End
+
+	Function Join<T>:String( args:T[] ) Where T Extends UNode
+		Local str:=""
+		For Local arg:=Eachin args
+			If str str+=","
+			str+=arg.ToString()
+		Next
+		Return str
+	End
+End
+
+
+Class PNode Extends UNode
 
 	Field srcfile:FileDecl
 	Field srcpos:Int
@@ -22,34 +39,33 @@ Class PNode
 		Self.endpos=endpos
 	End
 
-	Method ToString:String() Virtual
-		If srcfile Return srcfile.path+" ["+(srcpos Shr 12)+"]"
-		Return "? ["+(srcpos Shr 12)+"]"
-	End
-
 	Method ToDebugString:String() Virtual
 		If srcfile Return srcfile.path+" ["+(srcpos Shr 12)+"]"
 		Return "? ["+(srcpos Shr 12)+"]"
 	End
+	
 End
 
 Const SNODE_INIT:=0
 Const SNODE_SEMANTING:=1
 Const SNODE_SEMANTED:=2
 
-Class SNode
+Class SNode Extends UNode
 
 	Field pnode:PNode
 	Field semanted:SNode
 	Field state:Int
 	
 	Global semtab:String
-
+	
 	Method Semant:SNode()
 	
 		If state=SNODE_SEMANTED Or semanted Return semanted
 		
-		If state=SNODE_SEMANTING Throw New SemantEx( "Cyclic declaration of '"+ToString()+"'" )'"+pnode.ToString()+"'" )
+		If state=SNODE_SEMANTING 
+'			If Cast<Type>( Self ) Return Self
+			Throw New SemantEx( "Cyclic declaration of '"+ToString()+"'" )'"+pnode.ToString()+"'" )
+		Endif
 		
 		Try
 					
@@ -59,11 +75,13 @@ Class SNode
 			Endif
 
 			state=SNODE_SEMANTING
+			Scope.semanting.Push( Null )
 			PNode.semanting.Push( pnode )
 		
 			semanted=OnSemant()
 
 			PNode.semanting.Pop()
+			Scope.semanting.Pop()
 			state=SNODE_SEMANTED
 			
 			If DEBUG_SEMANTS And pnode 
@@ -76,6 +94,7 @@ Class SNode
 		Catch ex:SemantEx
 		
 			PNode.semanting.Pop()
+			Scope.semanting.Pop()
 			state=SNODE_SEMANTED
 			
 			If DEBUG_SEMANTS And pnode
@@ -93,12 +112,6 @@ Class SNode
 		Return Self
 	End
 	
-	Method ToString:String() Virtual
-		If pnode Return pnode.ToString()
-		Print String.FromCString( typeName() )
-		Return "????? SNode.ToString() ?????"
-	End
-	
 	Method ToType:Type() Virtual
 		SemantError( "SNode.ToType()" )
 		Return Null
@@ -110,4 +123,10 @@ Class SNode
 		Return Null
 	End
 	
+	Method ToString:String() override
+		If pnode Return pnode.ToString()
+		Print String.FromCString( typeName() )
+		Return "????? SNode.ToString() ?????"
+	End
+	
 End

+ 75 - 0
src/mx2cc/nodefinder.monkey2

@@ -0,0 +1,75 @@
+
+Namespace mx2
+
+Class NodeFinder
+
+	Field ident:String
+	Field findType:Bool
+	Field node:SNode
+	Field flist:FuncList
+	
+	Method New( ident:String,findType:Bool )
+		Self.ident=ident
+		Self.findType=findType
+	End
+	
+	Property Found:SNode()
+		Return node
+	End
+	
+	Method Find( scope:Scope )
+		If findType 
+			Add( scope.GetType( ident ) )
+		Else
+			Add( scope.GetNode( ident ) )
+		Endif
+	End
+	
+	Method Add( node:SNode )
+	
+		If Not node Return
+	
+		If Not Self.node
+			Self.node=node
+			Return
+		Endif
+		
+		Local flist:=Cast<FuncList>( node )
+		
+		If Self.flist
+		
+			If Not flist Throw New SemantEx( "Duplicate identifier '"+ident+"'" )
+			
+			AddFuncs( flist,Self.flist )
+			
+		Else If flist
+		
+			Local src:=Cast<FuncList>( Self.node )
+			If Not src Throw New SemantEx( "Duplicate identifier '"+ident+"'" )
+			
+			Local dst:=New FuncList( ident,Null )
+			
+			AddFuncs( src,dst )
+			AddFuncs( flist,dst )
+			
+			Self.flist=dst
+			Self.node=dst
+			
+		Else
+
+			Throw New SemantEx( "Duplicate identifier '"+ident+"'" )
+		
+		End
+	End
+
+	Method AddFuncs( src:FuncList,dst:FuncList )
+	
+		For Local func:=Eachin src.funcs
+			If dst.FindFunc( func.ftype.argTypes ) 
+				Throw New SemantEx( "Duplicate identifier '"+ident+"'" )
+			Endif
+			dst.funcs.Push( func )
+		Next
+	End
+	
+End

+ 81 - 30
src/mx2cc/parser.monkey2

@@ -91,6 +91,7 @@ Class Parser
 				Case "global"
 					ParseVars( decls,flags )
 				Case "field"
+					If flags & DECL_EXTENSION Error( "Fields cannot be declared in extension classes" )
 					If fileScope Error( "Fields can only be declared inside a class, struct or interface" )
 					ParseVars( decls,flags )
 				Case "local"
@@ -252,19 +253,41 @@ Class Parser
 	End
 	
 	Method ParseClass:ClassDecl( flags:Int )
-		
+	
 		Local decl:=New ClassDecl
 		decl.srcpos=SrcPos
 		decl.kind=Parse()
 		decl.docs=Docs()
 		decl.ident="?????"
 		
+		flags&=(DECL_ACCESSMASK|DECL_EXTERN)
+		
 		Try
 			decl.ident=ParseIdent()
 			
 			decl.genArgs=ParseGenArgs()
 			
+			If CParse( "extension" )
+			
+'				If decl.genArgs Error( "Extension classed cannot be generic" )
+				
+				decl.superType=New IdentExpr( decl.ident,decl.srcpos,decl.srcpos )
+
+				If decl.genArgs
+					Local exprs:=New Expr[decl.genArgs.Length]
+					For Local i:=0 Until decl.genArgs.Length
+						exprs[i]=New IdentExpr( decl.genArgs[i],decl.srcpos,decl.srcpos )
+					Next
+					decl.superType=New GenericExpr( decl.superType,exprs,decl.srcpos,decl.srcpos )
+				Endif
+				
+				flags|=DECL_EXTENSION
+			Endif
+			
 			If CParse( "extends" )
+			
+				If flags & DECL_EXTENSION Error( "Extension classes cannot use 'Extends'" )
+				
 				If decl.kind="interface" Or decl.kind="protocol"
 					decl.ifaceTypes=ParseTypes()
 				Else
@@ -273,13 +296,20 @@ Class Parser
 			Endif
 			
 			If CParse( "implements" )
+
+				If flags & DECL_EXTENSION Error( "Extension classes cannot implement interfaces" )
+				
 				If decl.kind<>"class" And decl.kind<>"struct" Error( "'Implements' can only be used with classes and structs" )
+				
 				decl.ifaceTypes=ParseTypes()
+
 			Endif
 			
 			Select Toke
 			Case "virtual","abstract","final"
-			
+
+				If flags & DECL_EXTENSION Error( "Extension classes cannot have modifiers" )
+				
 				If decl.kind="interface" Error( "Interfaces are implicitly abstract" )
 				
 				If decl.kind="protocol" Error( "Protocols cannot have modifiers" )
@@ -308,7 +338,8 @@ Class Parser
 		
 		decl.flags=flags
 		
-		Local mflags:=(flags & DECL_EXTERN) | DECL_PUBLIC
+		Local mflags:=(flags & (DECL_EXTERN|DECL_EXTENSION)) | DECL_PUBLIC
+
 		If decl.kind="interface" Or decl.kind="protocol" mflags|=DECL_IFACEMEMBER|DECL_ABSTRACT
 		
 		decl.members=ParseDecls( mflags,False )
@@ -358,6 +389,8 @@ Class Parser
 				flags|=DECL_OPERATOR
 			
 				Select Toke
+				Case "to"
+					ident=Parse()
 				Case "*","/","+","-","&","|","~~"
 					ident=Parse()
 				Case "*=","/=","+=","-=","&=","|=","~~="
@@ -376,7 +409,19 @@ Class Parser
 				
 			Case "method"
 			
-				If CParse( "new" ) ident="new" Else ident=ParseIdent()
+				If CParse( "new" )
+					ident="new"
+				Else If CParse( "to" )
+					ident="to"
+				Else
+					ident=ParseIdent()
+				Endif
+				
+			Case "function"
+			
+				flags&=~DECL_EXTENSION
+			
+				ident=ParseIdent()
 				
 			Default
 			
@@ -385,11 +430,13 @@ Class Parser
 	
 			genArgs=ParseGenArgs()
 			
+'			If genArgs And (flags & DECL_EXTENSION) Error( "Extension methods cannot be generic" )
+			
 			If CParse( ":" )
 				type=Cast<FuncTypeExpr>( ParseType() )
 				If Not type Error( "Expecting function type" )
 			Else
-				type=ParseFuncType( New IdentTypeExpr( "void",SrcPos,SrcPos ) )
+				type=ParseFuncType( New IdentExpr( "void",SrcPos,SrcPos ) )
 			Endif
 			
 			If Not (flags & DECL_EXTERN)
@@ -420,6 +467,8 @@ Class Parser
 			Select Toke
 			Case "virtual","abstract","override","final","extension"
 			
+				If (flags & DECL_EXTENSION) Error( "Extension methods cannot have modifiers" )
+			
 				If (flags & DECL_IFACEMEMBER) Error( "Interface methods are implictly abstract" )
 				
 				If CParse( "virtual" )
@@ -514,8 +563,6 @@ Class Parser
 		Try
 			decl.ident=ParseIdent()
 			
-			If CParse( "extends" ) decl.superType=ParseType()
-			
 			If CParse( "=" )
 				If Not (flags & DECL_EXTERN) Error( "Non-extern declaration cannot be assigned an extern symbol" )
 				decl.symbol=ParseString()
@@ -815,7 +862,7 @@ Class Parser
 		Local srcpos:=SrcPos
 		
 		Local varIdent:String
-		Local varType:TypeExpr
+		Local varType:Expr
 		Local varExpr:Expr
 		Local kind:String
 		Local init:Expr
@@ -973,7 +1020,7 @@ Class Parser
 			Bump()
 			
 			Local varIdent:String
-			Local varType:TypeExpr
+			Local varType:Expr
 			
 			Try
 				varIdent=ParseIdent()
@@ -1094,8 +1141,8 @@ Class Parser
 	End
 	
 	'THROWS!
-	Method ParseTypes:TypeExpr[]()
-		Local types:=New Stack<TypeExpr>
+	Method ParseTypes:Expr[]()
+		Local types:=New Stack<Expr>
 		Repeat
 			types.Push( ParseType() )
 		Until Not CParse( "," )
@@ -1103,7 +1150,7 @@ Class Parser
 	End
 	
 	'THROWS!
-	Method ParseFuncType:FuncTypeExpr( retType:TypeExpr )
+	Method ParseFuncType:FuncTypeExpr( retType:Expr )
 	
 		Parse( "(" )
 		
@@ -1126,7 +1173,7 @@ Class Parser
 						decl.type=ParseType()
 						If CParse( "=" ) decl.init=ParseExpr()
 					Else
-						decl.type=ParseType( New IdentTypeExpr( ident,decl.srcpos,EndPos ) )
+						decl.type=ParseType( New IdentExpr( ident,decl.srcpos,EndPos ) )
 					Endif
 				Else
 					decl.type=ParseType()
@@ -1146,20 +1193,20 @@ Class Parser
 	End
 	
 	'THROWS!
-	Method ParseIdentType:IdentTypeExpr()
+	Method ParseIdentType:IdentExpr()
 	
 		Local srcpos:=SrcPos
 		
 		Local ident:=CParseIdent()
 		If Not ident And IsTypeIdent( Toke ) ident=Parse()
 		If Not ident Error( "Expecting type identifier" )
-		Return New IdentTypeExpr( ident,srcpos,EndPos )
+		Return New IdentExpr( ident,srcpos,EndPos )
 	End
 
 	'THROWS!	
-	Method ParseBaseType:TypeExpr( identType:IdentTypeExpr=Null )
+	Method ParseBaseType:Expr( identType:IdentExpr=Null )
 	
-		Local type:TypeExpr=identType
+		Local type:Expr=identType
 		
 		If Not type type=ParseIdentType()
 		Local srcpos:=type.srcpos
@@ -1168,15 +1215,15 @@ Class Parser
 			If Toke="."
 				Bump()
 				Local ident:=ParseIdent()
-				type=New MemberTypeExpr( type,ident,srcpos,EndPos )
+				type=New MemberExpr( type,ident,srcpos,EndPos )
 			Else If Toke="<"
 				Bump()
-				Local args:=New Stack<TypeExpr>
+				Local args:=New Stack<Expr>
 				Repeat
 					args.Push( ParseType() )
 				Until Not CParse( "," )
 				Parse( ">" )
-				type=New GenericTypeExpr( type,args.ToArray(),srcpos,EndPos )
+				type=New GenericExpr( type,args.ToArray(),srcpos,EndPos )
 			Else
 				Exit
 			Endif
@@ -1190,7 +1237,7 @@ Class Parser
 	End
 	
 	'THROWS!
-	Method ParseType:TypeExpr( identType:IdentTypeExpr=Null )
+	Method ParseType:Expr( identType:IdentExpr=Null )
 	
 		Local type:=ParseBaseType( identType )
 		Local srcpos:=type.srcpos
@@ -1216,7 +1263,7 @@ Class Parser
 	End
 
 	'THROWS! Some ugly stunt parsing to handle operator New.
-	Method ParseNewType:TypeExpr()
+	Method ParseNewType:Expr()
 	
 		Local srcpos:=SrcPos
 		Local type:=ParseBaseType()
@@ -1339,7 +1386,7 @@ Class Parser
 				Local ident:=Parse()
 				
 				If Toke="ptr" Or Toke="("
-					Local type:=ParseBaseType( New IdentTypeExpr( ident,srcpos,EndPos ) )
+					Local type:=ParseBaseType( New IdentExpr( ident,srcpos,EndPos ) )
 					
 					Parse( "(" )
 					Local expr:=ParseExpr()
@@ -1359,7 +1406,7 @@ Class Parser
 		
 			Local toke:=Toke
 			Local tokeType:=TokeType
-			Local typeExpr:TypeExpr
+			Local typeExpr:Expr
 
 			Bump()
 			If CParse( ":" ) typeExpr=ParseType()
@@ -1370,7 +1417,7 @@ Class Parser
 
 			Local toke:=Toke
 			Local tokeType:=TokeType
-			Local typeExpr:TypeExpr
+			Local typeExpr:Expr
 
 			Bump()
 		
@@ -1413,7 +1460,7 @@ Class Parser
 				expr=New InvokeExpr( expr,args,srcpos,EndPos )
 			Case "<"
 				BeginTryParse()
-				Local args:=New Stack<TypeExpr>
+				Local args:=New Stack<Expr>
 				Try
 					Bump()
 					Repeat
@@ -1873,8 +1920,8 @@ Class Parser
 		Return "true"
 	End
 	
-	Method EvalError()
-		Error( "Failed to evaluate preprocessor expression: toke='"+Toke+"'" )
+	Method EvalError( msg:String )
+		Error( "Failed to evaluate preprocessor expression: "+msg )' toke='"+Toke+"'" )
 	End
 		
 	Method EvalPrimary:String()
@@ -1889,13 +1936,14 @@ Class Parser
 		Case TOKE_IDENT
 			Local id:=Parse()
 			Local t:=_ppsyms[id]
-			If Not t t="false"
+			If Not t EvalError( "Preprocessor symbol '"+id+"' not found" )
+'			If Not t t="false"
 			Return t
 		Case TOKE_STRINGLIT
 			Return Parse()
 		End
 
-		EvalError()
+		EvalError( "Failed to evaludate preprocessor expression - unexpected token '"+Toke+"'" )
 		Return Null
 	End
 	
@@ -1916,6 +1964,9 @@ Class Parser
 				lhs=ToBool( lhs )
 				rhs=ToBool( rhs )
 			Endif
+			If (lhs="~q"+HostOS+"~q" And rhs="~qdesktop~q") Or (lhs="~qdesktop~q" And rhs="~q"+HostOS+"~q" ) 
+				EvalError( "__TARGET__=~qdesktop~q no longer supported! Use boolean __DESKTOP_TARGET__ instead!" )
+			Endif
 			Select op
 			Case "=" If lhs=rhs lhs="true" Else lhs="false"
 			Case "<>" If lhs<>rhs lhs="true" Else lhs="false"

+ 5 - 336
src/mx2cc/scope.monkey2

@@ -13,6 +13,9 @@ Class Scope
 	'what translator needs to emit
 	Field transMembers:=New Stack<SNode>
 	
+	'easier than passing classes around!
+	Global semanting:=New Stack<Scope>
+	
 	Method New( outer:Scope )
 		Self.outer=outer
 		If outer outer.inner.Push( Self )
@@ -135,342 +138,8 @@ Class Scope
 		Return Null
 	End
 	
-End
-
-Class FileScope Extends Scope
-
-	Field fdecl:FileDecl
-	
-	Field nmspace:NamespaceScope
-	
-	Field usings:Stack<NamespaceScope>
-	
-	Field toSemant:=New Stack<SNode>
-	
-	Method New( fdecl:FileDecl )
-		Super.New( Null )
-		
-		Local module:=fdecl.module
-
-		Self.fdecl=fdecl
-		Self.usings=module.usings
-		
-		Local builder:=Builder.instance
-		
-		nmspace=builder.GetNamespace( fdecl.nmspace )
-		nmspace.inner.Push( Self )
-		outer=nmspace
-		
-		#rem
-		For Local use:=Eachin fdecl.usings
-			Local nmspace:=builder.GetNamespace( use )
-			If usings.Contains( nmspace ) Continue
-			usings.Push( nmspace )
-		Next
-		#end
-		
-		For Local member:=Eachin fdecl.members
-
-			Local node:=member.ToNode( Self )
-			
-			If member.IsPublic
-				If Not nmspace.Insert( member.ident,node ) Continue
-			Else
-				If Not Insert( member.ident,node ) Continue
-			Endif
-
-			toSemant.Push( node )
-		Next
-	End
-	
-	Method UsingNamespace:Bool( nmspace:NamespaceScope )
-		If usings.Contains( nmspace ) Return True
-		usings.Push( nmspace )
-		Return False
-	End
-		
-	Method UsingInner( nmspace:NamespaceScope )
-		For Local scope:=Eachin nmspace.inner
-			Local nmspace:=Cast<NamespaceScope>( scope )
-			If nmspace UsingNamespace( nmspace )
-		Next
-	End
-	
-	Method UsingAll( nmspace:NamespaceScope )
-		If UsingNamespace( nmspace ) Return
-		For Local scope:=Eachin nmspace.inner
-			Local nmspace:=Cast<NamespaceScope>( scope )
-			If nmspace UsingAll( nmspace )
-		Next
-	End
-	
-	Method Semant()
-	
-'		Print "Semating:"+fdecl.path
-
-		Local builder:=Builder.instance
-		
-		If nmspace<>builder.monkeyNamespace
-			UsingAll( builder.monkeyNamespace )
-		Endif
-
-		For Local use:=Eachin fdecl.usings
-		
-			If use="*"
-				UsingAll( builder.rootNamespace )
-				Continue
-			Endif
-		
-			If use.EndsWith( ".." )
-				Local nmspace:=builder.GetNamespace( use.Slice( 0,-2 ) )
-				UsingAll( nmspace )
-				Continue
-			Endif
-		
-			If use.EndsWith( ".*" )
-				Local nmspace:=builder.GetNamespace( use.Slice( 0,-2 ) )
-				UsingInner( nmspace )
-				Continue
-			Endif
-			
-			Local nmspace:=builder.GetNamespace( use )
-			If nmspace UsingNamespace( nmspace )
-		Next
-	
-		For Local node:=Eachin toSemant
-			Try			
-				node.Semant()
-			Catch ex:SemantEx
-			End
-		Next
-		
-	End
-	
-	Method FindNode:SNode( ident:String ) Override
-	
-		Local node:=GetNode( ident )
-		If node Return node
-	
-		Local flist:FuncList
-	
-		For Local scope:=Eachin usings
-		
-			Local node2:=scope.GetNode( ident )
-			If Not node2 Continue
-			
-			If Not node
-				node=node2
-				Continue
-			Endif
-			
-			Local flist2:=Cast<FuncList>( node2 )
-
-			If flist2
-			
-				If Not flist
-					Local flist2:=Cast<FuncList>( node )
-					If flist2 flist=New FuncList( flist2.ident,Self )
-				Endif
-				
-				If flist
-					For Local func:=Eachin flist2.funcs
-						If flist.FindFunc( func.ftype.argTypes ) 
-							Throw New SemantEx( "Duplicate identifier '"+ident+"'" )
-						Endif
-						flist.funcs.Push( func )
-					Next
-					Continue
-				Endif
-				
-			Endif
-			
-			Throw New SemantEx( "Duplicate identifier '"+ident+"'" )
-		Next
-		
-		If flist Return flist
-		
-		If node Return node
-		
-		If outer Return outer.FindNode( ident )
-		
-		Return Null
-	End
-	
-	Method FindType:Type( ident:String ) Override
-	
-		Local type:=GetType( ident )
-		If type Return type
-		
-		For Local scope:=Eachin usings
-		
-			Local type2:=scope.GetType( ident )
-			If Not type2 Continue
-			
-			If type Throw New SemantEx( "Duplicate identifier '"+ident+"'" )
-			
-			type=type2
-		Next
-		
-		If type Return type
-		
-		If outer Return outer.FindType( ident )
-		
+	Function Semanting:Scope()
+		If semanting.Length Return semanting.Top
 		Return Null
 	End
-		
-	Method FindFile:FileScope() Override
-
-		Return Self
-	End
-	
-End
-
-Class Block Extends Scope
-
-	Field func:FuncValue
-
-	Field stmts:=New Stack<Stmt>
-	
-	Field reachable:Bool=True
-	
-	Field loop:Bool
-	Field inex:Bool
-	
-	Method New( func:FuncValue )
-		Super.New( func.scope )
-		
-		Self.func=func
-	End
-	
-	Method New( outer:Block )
-		Super.New( outer )
-		
-		func=outer.func
-		loop=outer.loop
-		inex=outer.inex
-	End
-	
-'	Property IsGeneric:Bool() Override
-
-'		If func.IsGeneric Return True
-
-'		Return Super.IsGeneric
-'	End
-
-	Method FindValue:Value( ident:String ) Override
-
-		Local node:=FindNode( ident )
-		If Not node Return Null
-		
-		Local vvar:=Cast<VarValue>( node )
-		If vvar
-		
-			Select vvar.vdecl.kind
-			Case "local","param","capture"
-			
-				Local vfunc:=Cast<Block>( vvar.scope ).func
-				
-				If vfunc<>func
-				
-					If func.fdecl.kind<>"lambda" Return Null
-					
-					'capture vvar...
-					'
-					'find all funcs (lambdas) up to vvar func
-					'
-					Local tfunc:=func,funcs:=New Stack<FuncValue>
-
-					While tfunc<>vfunc
-						funcs.Push( tfunc )
-						tfunc=Cast<Block>( tfunc.block.outer ).func
-					Wend
-					
-					While Not funcs.Empty
-					
-						Local tfunc:=funcs.Pop()
-						
-						'FXIME: this pollutes outer func scope with captured var name.
-						'
-						vvar=New VarValue( "capture",vvar.vdecl.ident,vvar,tfunc.block )
-						tfunc.block.Insert( vvar.vdecl.ident,vvar )
-						tfunc.captures.Push( vvar )
-					
-					Wend
-					
-					node=vvar
-					
-				Endif
-			End
-			
-		Endif
-		
-		Return node.ToValue( func.selfValue )
-	End
-	
-	Method Emit( stmt:Stmt )
-	
-		If reachable stmts.Push( stmt )
-	End
-	
-	Method Semant( stmts:StmtExpr[] )
-	
-		For Local expr:=Eachin stmts
-			Try
-
-				Local stmt:=expr.Semant( Self )
-				If stmt Emit( stmt )
-				
-			Catch ex:SemantEx
-			End
-		Next
-	End
-	
-	Method AllocLocal:VarValue( init:Value )
-
-		Local ident:=""+func.nextLocalId
-		func.nextLocalId+=1
-
-		Local varValue:=New VarValue( "local",ident,init,Self )
-		
-		stmts.Push( New VarDeclStmt( Null,varValue ) )
-
-		Return varValue
-	End
-
-	Method AllocLocal:VarValue( ident:String,init:Value )
-
-		Local varValue:=New VarValue( "local",ident,init,Self )
-		
-		stmts.Push( New VarDeclStmt( Null,varValue ) )
-
-		Insert( ident,varValue )
-
-		Return varValue
-	End
-	
-End
-
-Class FuncBlock Extends Block
-
-	Method New( func:FuncValue )
-
-		Super.New( func )
-	End
-	
-	Property IsGeneric:Bool() Override
-	
-		If func.IsGeneric Return True
-		
-		Return Super.IsGeneric
-	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
-
-		Return Super.FindType( ident )
-	End
-
 End

+ 7 - 7
src/mx2cc/stmtexpr.monkey2

@@ -547,7 +547,7 @@ End
 Class ForStmtExpr Extends StmtExpr
 
 	Field varIdent:String
-	Field varType:TypeExpr
+	Field varType:Expr
 	Field varExpr:Expr
 	Field kind:String
 	Field init:Expr
@@ -556,7 +556,7 @@ Class ForStmtExpr Extends StmtExpr
 	
 	Field stmts:StmtExpr[]
 	
-	Method New( varIdent:String,varType:TypeExpr,varExpr:Expr,kind:String,init:Expr,cond:Expr,incr:Expr,stmts:StmtExpr[],srcpos:Int,endpos:Int )
+	Method New( varIdent:String,varType:Expr,varExpr:Expr,kind:String,init:Expr,cond:Expr,incr:Expr,stmts:StmtExpr[],srcpos:Int,endpos:Int )
 		Super.New( srcpos,endpos )
 		
 		Self.varIdent=varIdent
@@ -674,7 +674,7 @@ Class ForStmtExpr Extends StmtExpr
 		Endif
 		
 		If varIdent
-			If varType curr=curr.UpCast( varType.Semant( block ) )
+			If varType curr=curr.UpCast( varType.SemantType( block ) )
 			block.AllocLocal( varIdent,curr )
 		Else
 			Local iter:=varExpr.Semant( block ).RemoveSideEffects( block )
@@ -699,7 +699,7 @@ Class ForStmtExpr Extends StmtExpr
 		Local init:=Self.init.SemantRValue( iblock )
 		
 		If varIdent
-			If varType init=init.UpCast( varType.Semant( iblock ) )
+			If varType init=init.UpCast( varType.SemantType( iblock ) )
 			iter=iblock.AllocLocal( varIdent,init )
 		Else
 			iter=varExpr.Semant( iblock ).RemoveSideEffects( iblock )
@@ -758,10 +758,10 @@ End
 Class CatchExpr
 
 	Field varIdent:String
-	Field varType:TypeExpr
+	Field varType:Expr
 	Field stmts:StmtExpr[]
 
-	Method New( varIdent:String,varType:TypeExpr,stmts:StmtExpr[] )
+	Method New( varIdent:String,varType:Expr,stmts:StmtExpr[] )
 		Self.varIdent=varIdent
 		Self.varType=varType
 		Self.stmts=stmts
@@ -796,7 +796,7 @@ Class TryStmtExpr Extends StmtExpr
 			Local vvar:VarValue
 
 			If cexpr.varType
-				Local type:=cexpr.varType.Semant( iblock )
+				Local type:=cexpr.varType.SemantType( iblock )
 				vvar=New VarValue( "local",cexpr.varIdent,New LiteralValue( type,"" ),iblock )
 				iblock.Insert( cexpr.varIdent,vvar )
 			Endif

+ 1 - 119
src/mx2cc/test.monkey2

@@ -9,44 +9,9 @@ Using mojo..
 
 Class MyWindow Extends Window
 
-	Method New()
-	
-		ClearColor=Color.Magenta
-	
-		Local stream:=Stream.Open( "asset::fonts/DejaVuSans.ttf","r" )
-		
-		If stream
-			Print "Stream opened!"
-			Print "Length="+stream.Length
-			stream.Close()
-			If Font.Open( "asset::fonts/DejaVuSans.ttf",16 )
-				Print "Font opened!"
-			Else
-				Print "Font failed!"
-			Endif
-		Else
-			Print "Failed to open stream"
-		Endif
-		
-	End
-
 	Method OnRender( canvas:Canvas ) Override
 	
-		Print "Render!"
-		
-		RequestRender()
-	
-	#rem
-		canvas.Clear( Color.Blue )
-		
-		canvas.Color=Color.Red
-		
-		canvas.DrawRect( 16,16,64,64 )
-		
-		canvas.Color=Color.Yellow
-		
-		canvas.DrawText( "Fuck yeah!",Width/2,Height/2,.5,.5 )
-	#end
+		canvas.DrawText( "Hello World",Width/2,Height/2,.5,.5 )
 	
 	End
 	
@@ -54,92 +19,9 @@ End
 
 Function Main()
 
-	Print "HELLO WORLD!"
-
 	New AppInstance
 	
 	New MyWindow
 	
 	App.Run()
 End
-
-#rem
-
-#import "<libc>"
-#import "<sdl2>"
-#import "<gles20>"
-
-Namespace sdl2test
-
-Using libc..
-Using sdl2..
-Using gles20..
-
-Class SdlWindow
-
-	Field sdlWindow:SDL_Window Ptr
-	Field sdlGLContext:SDL_GLContext
-	
-	Method New()
-	
-		SDL_Init( SDL_INIT_EVERYTHING )
-		
-		sdlWindow=SDL_CreateWindow( "SDL2 OpenGL Window",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,640,480,SDL_WINDOW_OPENGL )
-		
-		sdlGLContext=SDL_GL_CreateContext( sdlWindow )
-		
-		SDL_GL_MakeCurrent( sdlWindow,sdlGLContext )
-	End
-	
-	Method Run()
-	
-		Repeat
-		
-			Local event:SDL_Event
-			
-			While( SDL_PollEvent( Varptr event ) )
-		
-				Select event.type
-					
-				Case SDL_WINDOWEVENT
-		
-					Local wevent:=Cast<SDL_WindowEvent Ptr>( Varptr event )
-			
-					Select wevent->event
-					
-					Case SDL_WINDOWEVENT_CLOSE
-					
-						exit_( 0 )
-					
-					End
-					
-				End
-
-			Wend
-			
-			OnRender()
-			
-			SDL_GL_SwapWindow( sdlWindow )
-		Forever
-		
-	End
-	
-	Method OnRender()
-	
-		glClearColor( 1,1,0,1 )
-		
-		glClear( GL_COLOR_BUFFER_BIT )
-	End
-	
-End
-
-
-Function Main()
-
-	Local window:=New SdlWindow
-	
-	window.Run()
-
-End
-
-#end

+ 7 - 28
src/mx2cc/test2.monkey2

@@ -1,35 +1,14 @@
 
 #Import "<std>"
-#Import "<mojo>"
 
 Using std..
-Using mojo..
 
-Class MyWindow Extends Window
-	Field t:Test
-	
-	Method New(title:String, width:Int, height:Int)
-		Super.New(title, width, height, WindowFlags.Resizable)
-		ClearColor = Color.Black
-		SwapInterval=1
-		t = New Test()		
-	End
-	
-	Method OnRender( canvas:Canvas ) Override
-		App.RequestRender()
-		canvas.DrawText( "Hello World!",Width/2,Height/2,.5,.5 )
-		Local x:=t.Hop()
-	End
-End
+Const TestDoc:="
+Hello World!
+"
+ 
+Function Main()
 
-Class Test
-	Method Hop()
-		Print "Hop"
-	End
+	Print "TestDoc="+TestDoc+"END"
+	
 End
-
-Function Main()
-	New AppInstance
-	New MyWindow("Hello World", 640, 480)
-	App.Run()
-End

+ 6 - 1
src/mx2cc/toker.monkey2

@@ -226,7 +226,12 @@ Class Toker
 		
 			While _pos<_len
 				Local ch:=_text[_pos]
-				If ch=CHAR_QUOTE Or ch=CHAR_EOL Exit
+				If ch=CHAR_QUOTE Exit
+				If ch=CHAR_EOL
+					_line+=1
+					_linePos=_pos
+				
+				Endif
 				_pos+=1
 			Wend
 			If _pos<_len And _text[_pos]=CHAR_QUOTE

+ 1 - 2
src/mx2cc/translator.monkey2

@@ -58,8 +58,7 @@ Class Translator
 	Field debug:Bool
 	
 	Method New()
-		Local builder:=Builder.instance
-		Self.debug=builder.opts.config="debug"
+		Self.debug=Builder.opts.config="debug"
 	End
 	
 	Method Trans:String( value:Value ) Abstract

+ 19 - 16
src/mx2cc/translator_cpp.monkey2

@@ -224,7 +224,7 @@ Class Translator_CPP Extends Translator
 		If Not func.IsCtor retType=TransType( ftype.retType )+" "
 
 		Local params:=""
-		If func.IsExtension params=TransType( ctype )+" l_self"
+		If func.IsExtension params=TransType( func.selfType )+" l_self"
 
 		For Local p:=Eachin func.params
 			If params params+=","
@@ -322,22 +322,26 @@ Class Translator_CPP Extends Translator
 				xtends="public bbObject"
 			Endif
 			
+		Case "struct"
+
+			If ctype.superType
+				Uses( ctype.superType )
+				superName=ClassName( ctype.superType )
+				xtends="public "+superName
+			Endif
+		
 		Case "interface"
 		
 			If Not ctype.ifaceTypes xtends="public bbInterface"
 			
-		Case "struct"
-		
 		End
 		
-		If cdecl.kind<>"struct"
-			For Local iface:=Eachin ctype.ifaceTypes
-				If iface.cdecl.kind="protocol" Continue
-				Uses( iface )
-				If xtends xtends+=","
-				xtends+="public virtual "+ClassName( iface )
-			Next
-		Endif
+		For Local iface:=Eachin ctype.ifaceTypes
+			If iface.cdecl.kind="protocol" Continue
+			Uses( iface )
+			If xtends xtends+=","
+			xtends+="public virtual "+ClassName( iface )
+		Next
 		
 		If xtends xtends=" : "+xtends
 		
@@ -355,7 +359,7 @@ Class Translator_CPP Extends Translator
 				If Not flist Or it.Key="new" Continue
 				
 				For Local func:=Eachin flist.funcs
-					If Not func.IsMethod Or func.scope<>ctype.superType.scope Continue
+					If Not func.IsMethod Or func.scope<>ctype.superType.scope Continue	'Or func.fdecl.IsExtension Continue
 					Local sym:=FuncName( func )
 					If done[sym] Continue
 					done[sym]=True
@@ -720,10 +724,9 @@ Class Translator_CPP Extends Translator
 			Emit( "if(done) return;" )
 			Emit( "done=true;" )
 			
-			Local builder:=Builder.instance
 			For Local dep:=Eachin module.moduleDeps.Keys
 			
-				Local mod2:=builder.modulesMap[dep]
+				Local mod2:=Builder.modulesMap[dep]
 				
 				If mod2.main
 					Emit( "void mx2_"+mod2.ident+"_main();mx2_"+mod2.ident+"_main();" )
@@ -850,10 +853,10 @@ Class Translator_CPP Extends Translator
 				
 				Select func.cscope.ctype.cdecl.kind
 				Case "struct"
-					Emit( ClassName( func.cscope.ctype )+"*self=&"+Trans(func.selfValue)+";" )
+					Emit( ClassName( func.selfType )+"*self=&"+Trans( func.selfValue )+";" )
 					Emit( "bbDBLocal(~qSelf~q,self);" )
 				Case "class"
-					Emit( ClassName( func.cscope.ctype )+"*self="+Trans(func.selfValue)+";" )
+					Emit( ClassName( func.selfType )+"*self="+Trans( func.selfValue )+";" )
 					Emit( "bbDBLocal(~qSelf~q,&self);" )
 				End
 				

+ 32 - 31
src/mx2cc/type.monkey2

@@ -34,6 +34,7 @@ Class Type Extends SNode
 	Global ExceptionClass:ClassType
 	
 	Field _alias:Type
+	
 	Field flags:Int
 	
 	Method New()
@@ -87,18 +88,8 @@ Class Type Extends SNode
 		Return Null
 	End
 	
-	Method Invoke:Value( args:Value[],value:Value ) Virtual
-		Throw New SemantEx( "Type '"+ToString()+"' cannot be invoked" )
-		Return Null
-	End
-	
-	Method Index:Value( args:Value[],value:Value ) Virtual
-		Throw New SemantEx( "Type '"+ToString()+"' cannot be indexed" )
-		Return Null
-	End
-	
-	Method GenInstance:Type( types:Type[] ) Virtual
-		Throw New SemantEx( "Type '"+ToString()+"' is not generic" )
+	Method InferType:Type( type:Type,args:Type[] ) Virtual
+		If Equals( type ) Return type	
 		Return Null
 	End
 	
@@ -106,21 +97,37 @@ Class Type Extends SNode
 		Return type=Self
 	End
 	
-	Method DistanceToType:Int( type:Type ) Virtual
-		If Equals( type ) Return 0
-		Return -1
-	End
-	
 	Method ExtendsType:Bool( type:Type ) Virtual
 		Return Equals( type )
 	End
 	
+	Method DistanceToType:Int( type:Type ) Virtual
+		Return Equals( type ) ? 0 Else -1
+	End
+	
 	Method CanCastToType:Bool( type:Type ) Virtual
 		Return Equals( type )
 	End
 
-	Method InferType:Type( type:Type,args:Type[] ) Virtual
-		If Equals( type ) Return type	
+	Method UpCast:Value( rvalue:Value,type:Type ) Virtual
+		Local d:=DistanceToType( type )
+		If d<0 Throw New UpCastEx( rvalue,type )
+		If d>0 Return New UpCastValue( type,rvalue )
+		Return rvalue
+	End
+
+	Method Invoke:Value( args:Value[],value:Value ) Virtual
+		Throw New SemantEx( "Type '"+ToString()+"' cannot be invoked" )
+		Return Null
+	End
+	
+	Method Index:Value( args:Value[],value:Value ) Virtual
+		Throw New SemantEx( "Type '"+ToString()+"' cannot be indexed" )
+		Return Null
+	End
+	
+	Method GenInstance:Type( types:Type[] ) Virtual
+		Throw New SemantEx( "Type '"+ToString()+"' is not generic" )
 		Return Null
 	End
 	
@@ -152,6 +159,10 @@ Class ProxyType Extends Type
 		Return _alias.FindType( ident )
 	End
 	
+	Method UpCast:Value( rvalue:Value,type:Type ) Override
+		Return _alias.UpCast( rvalue,type )
+	End
+	
 	Method Invoke:Value( args:Value[],value:Value ) Override
 		Return _alias.Invoke( args,value )
 	End
@@ -264,15 +275,6 @@ Class PrimType Extends Type
 		
 		End
 		
-		#rem
-		If TCast<PrimType>( type ) Return MAX_DISTANCE
-		
-		Select type
-		Case CStringClass,WStringClass,Utf8StringClass
-			Return MAX_DISTANCE
-		End
-		#end
-		
 		Return -1
 	End
 	
@@ -282,9 +284,8 @@ Class PrimType Extends Type
 	End
 	
 	Method CanCastToType:Bool( type:Type ) Override
-		
-		'prim->prim
-		If TCast<PrimType>( type ) Return True
+	
+		If DistanceToType( type )>=0 Return True
 		
 		'integral->enum
 		If IsIntegral And TCast<EnumType>( type ) Return True

+ 0 - 213
src/mx2cc/typeexpr.monkey2

@@ -1,213 +0,0 @@
-
-Namespace mx2
-
-Function SemantTypes:Type[]( exprs:TypeExpr[],scope:Scope )
-	Local types:=New Type[exprs.Length]
-	For Local i:=0 Until types.Length
-		types[i]=exprs[i].Semant( scope )
-	Next
-	Return types
-End
-
-Class TypeExpr Extends PNode
-
-	Method New( srcpos:Int,endpos:Int )
-		Self.srcpos=srcpos
-		Self.endpos=endpos
-	End
-	
-	Method OnSemant:Type( scope:Scope ) Virtual
-		SemantError( "TypeExpr.Semant()" )
-		Return Null
-	End
-	
-	Method Semant:Type( scope:Scope,generic:Bool=False )
-	
-		Try
-		
-			PNode.semanting.Push( Self )
-			
-			Local type:=OnSemant( scope )
-			
-			Local ctype:=TCast<ClassType>( type )
-			If ctype
-				If generic
-'					If Not ctype.types Or ctype.instanceOf Throw New SemantEx( "Type '"+ctype.ToString()+"' is not generic" )
-				Else
-					If ctype.types And Not ctype.instanceOf Throw New SemantEx( "Type '"+ctype.ToString()+" is generic" )
-				Endif
-			Endif
-			
-			PNode.semanting.Pop()
-			Return type
-		
-		Catch ex:SemantEx
-		
-			PNode.semanting.Pop()
-			Throw ex
-		End
-
-		Return Null
-	End
-	
-End
-
-Class IdentTypeExpr Extends TypeExpr
-
-	Field ident:String
-	
-	Method New( ident:String,srcpos:Int,endpos:Int )
-		Super.New( srcpos,endpos )
-		Self.ident=ident
-	End
-	
-	Method ToString:String() Override
-		Select ident
-		Case "void","bool","byte","short","int","long","ubyte","ushort","uint","ulong","float","double","string","object"
-			Return ident.Capitalize()
-		End
-		Return ident
-	End
-	
-	Method OnSemant:Type( scope:Scope ) Override
-	
-		Local type:=scope.FindType( ident )
-		If Not type Throw New TypeIdentEx( ident )
-		
-		Return type
-	End
-	
-End
-
-Class FuncTypeExpr Extends TypeExpr
-
-	Field retType:TypeExpr
-	Field params:VarDecl[]
-
-	Method New( retType:TypeExpr,params:VarDecl[],srcpos:Int,endpos:Int )
-		Super.New( srcpos,endpos )
-		Self.retType=retType
-		Self.params=params
-	End
-
-	Method ToString:String() Override
-		Local str:=""
-		If retType str=retType.ToString()
-		Return str+"("+Join( params )+")"
-	End
-
-	Method OnSemant:Type( scope:Scope ) Override
-
-		Local retType:=Self.retType.Semant( scope )
-		
-		Local argTypes:=New Type[params.Length]
-		For Local i:=0 Until argTypes.Length
-			argTypes[i]=params[i].type.Semant( scope )
-		Next
-		
-		Return New FuncType( retType,argTypes )
-	End
-	
-End
-
-Class MemberTypeExpr Extends TypeExpr
-
-	Field type:TypeExpr
-	Field ident:String
-	
-	Method New( type:TypeExpr,ident:String,srcpos:Int,endpos:Int )
-		Super.New( srcpos,endpos )
-		Self.type=type
-		Self.ident=ident
-	End
-	
-	Method ToString:String() Override
-		Return type.ToString()+"."+ident
-	End
-	
-	Method OnSemant:Type( scope:Scope ) Override
-	
-		Local type:=Self.type.Semant( scope )
-		
-		type=type.FindType( ident )
-		If Not type Throw New TypeIdentEx( ident )
-		
-		Return type
-	End
-	
-End
-
-Class ArrayTypeExpr Extends TypeExpr
-
-	Field type:TypeExpr
-	Field rank:Int
-	
-	Method New( type:TypeExpr,rank:Int,srcpos:Int,endpos:Int )
-		Super.New( srcpos,endpos )
-		Self.type=type
-		Self.rank=rank
-	End
-	
-	Method ToString:String() Override
-		Return type.ToString()+"[,,,,,,,,,,,".Slice( 0,rank )+"]"
-	End
-	
-	Method OnSemant:Type( scope:Scope ) Override
-	
-		Local type:=Self.type.Semant( scope )
-		
-		Return New ArrayType( type,rank )
-	End
-
-End
-
-Class GenericTypeExpr Extends TypeExpr
-
-	Field type:TypeExpr
-	Field args:TypeExpr[]
-	
-	Method New( type:TypeExpr,args:TypeExpr[],srcpos:Int,endpos:Int )
-		Super.New( srcpos,endpos )
-		Self.type=type
-		Self.args=args
-	End
-	
-	Method ToString:String() Override
-		Return type.ToString()+"<"+Join( args )+">"
-	End
-	
-	Method OnSemant:Type( scope:Scope ) Override
-	
-		Local type:=Self.type.Semant( scope,True )
-		
-		Local args:=New Type[Self.args.Length]
-		For Local i:=0 Until args.Length
-			args[i]=Self.args[i].Semant( scope )
-		Next
-		
-		Return type.GenInstance( args )
-	End
-
-End
-
-Class PointerTypeExpr Extends TypeExpr
-
-	Field type:TypeExpr
-	
-	Method New( type:TypeExpr,srcpos:Int,endpos:Int )
-		Super.New( srcpos,endpos )
-		
-		Self.type=type
-	End
-	
-	Method ToString:String() Override
-		Return type.ToString()+" Ptr"
-	End
-	
-	Method OnSemant:Type( scope:Scope ) Override
-	
-		Local type:=Self.type.Semant( scope )
-		
-		Return New PointerType( type )
-	End
-End

+ 1 - 40
src/mx2cc/value.monkey2

@@ -39,10 +39,7 @@ Class Value Extends SNode
 	
 	Method UpCast:Value( type:Type ) Virtual
 		Local rvalue:=ToRValue()
-		Local d:=rvalue.type.DistanceToType( type )
-		If d<0 Throw New UpCastEx( rvalue,type )
-		If d>0 Return New UpCastValue( type,rvalue )
-		Return rvalue
+		Return rvalue.type.UpCast( rvalue,type )
 	End
 	
 	Method FindValue:Value( ident:String ) Virtual
@@ -71,11 +68,6 @@ Class Value Extends SNode
 		
 		Local rtype:=BalanceAssignTypes( op,type,value.type )
 		Return New AssignStmt( pnode,op,Self,value.UpCast( rtype ) )
-		
-'		ValidateAssignOp( op,type )
-'		value=value.UpCast( type )
-'		Return New AssignStmt( pnode,op,Self,value )
-
 	End
 	
 	Method CheckAccess( tscope:Scope ) Virtual
@@ -119,37 +111,6 @@ Class Value Extends SNode
 		
 	End
 	
-	#rem
-	Function IsValidAssignOp:Bool( op:String,type:Type )
-
-		If op="=" Return True
-
-		Local ptype:=TCast<PrimType>( type )
-		If ptype
-			Select op
-			Case "+=" Return ptype=Type.StringType Or ptype.IsNumeric
-			Case "*=","/=","mod=","-=" Return ptype.IsNumeric
-			Case "&=","|=","~=" Return ptype.IsIntegral
-			Case "shl=","shr=" Return ptype.IsIntegral
-			Case "and","or" Return ptype=Type.BoolType
-			End
-			Return False
-		Endif
-		
-		If TCast<EnumType>( type ) Return op="&=" Or op="|=" Or op="~="
-		
-		If TCast<PointerType>( type ) Return op="+=" Or op="-="
-		
-		If TCast<FuncType>( type ) Return op="+=" Or op="-="
-		
-		Return False
-	End
-	
-	Function ValidateAssignOp( op:String,type:Type )
-		If Not IsValidAssignOp( op,type ) Throw New SemantEx( "Assignment operator '"+op+"' cannot be used with type '"+type.ToString()+"'" )
-	End
-	#end
-	
 End
 
 Class TypeValue Extends Value

+ 13 - 22
src/mx2cc/var.monkey2

@@ -3,33 +3,20 @@ Namespace mx2
 
 Class VarDecl Extends Decl
 
-	Field type:TypeExpr
+	Field type:Expr
 	Field init:Expr
 	
-	Method ToString:String() Override
-	
-		Local str:=""
-		If kind="param"
-			str=ident
-		Else
-			str=Super.ToString()
-		Endif
-		
-		If type
-			If str str+=":"
-			str+=type.ToString()
-			If init str+="="+init.ToString()
-		Else If init
-			str+=":="+init.ToString()
-		Endif
-		
-		Return str
-	End
-	
 	Method ToNode:SNode( scope:Scope ) Override
 	
 		Return New VarValue( Self,scope )
 	End
+	
+	Method ToString:String() Override
+		Local str:=Super.ToString()+":"
+		If type str+=type.ToString()
+		If init str+="="+init.ToString()
+		Return str
+	End
 
 End
 
@@ -76,8 +63,10 @@ Class VarValue Extends Value
 	
 	Method OnSemant:SNode() Override
 	
+		Scope.semanting.Push( scope )
+	
 		If vdecl.type
-			type=vdecl.type.Semant( scope )
+			type=vdecl.type.SemantType( scope )
 			If vdecl.init init=vdecl.init.SemantRValue( scope,type )
 		Else If vdecl.init
 			init=vdecl.init.SemantRValue( scope )
@@ -96,6 +85,8 @@ Class VarValue Extends Value
 			Endif
 			
 		Endif
+		
+		Scope.semanting.Pop()
 	
 		Return Self
 	End