浏览代码

Merge pull request #330 from HurryStarfish/finally

Finally blocks
Brucey 7 年之前
父节点
当前提交
b299886c7f

文件差异内容过多而无法显示
+ 1011 - 1011
ctranslator.bmx


+ 36 - 4
decl.bmx

@@ -224,7 +224,6 @@ Type TDecl
 	End Method
 	
 	Method AssertAccess()
-If ident="abc" DebugStop
 		If Not CheckAccess()
 			If IsPrivate() Then
 				Err ToString() +" is private."
@@ -1637,10 +1636,12 @@ End Type
 Type TBlockDecl Extends TScopeDecl
 	Field stmts:TList=New TList
 	Field extra:Object
+	Field isFinallyBlock:Int
 	
-	Method Create:TBlockDecl( scope:TScopeDecl, generated:Int = False )
-		Self.scope=scope
+	Method Create:TBlockDecl( scope:TScopeDecl, generated:Int = False, isFinallyBlock:Int = False )
+		Self.scope = scope
 		Self.generated = generated
+		Self.isFinallyBlock = isFinallyBlock
 		
 		attrs :| (scope.attrs & DECL_NODEBUG)
 		
@@ -1679,6 +1680,37 @@ Type TBlockDecl Extends TScopeDecl
 		
 		For Local stmt:TStmt=EachIn stmts
 			stmt.Semant
+			
+			If TReturnStmt(stmt) Then
+				If SurroundingFinallyBlock(Self) Then PushErr stmt.errInfo; Err "Return cannot be used inside a Finally block."
+			Else If TBreakStmt(stmt) Then
+				Local loop:TLoopStmt
+				If TLoopLabelExpr(TBreakStmt(stmt).label) Then
+					loop = TLoopLabelExpr(TBreakStmt(stmt).label).loop
+				Else
+					loop = TLoopStmt(Self.FindLoop())
+				End If
+				Local f:TBlockDecl = SurroundingFinallyBlock(Self)
+				If f And f <> SurroundingFinallyBlock(loop.block) Then PushErr stmt.errInfo; Err "Exit cannot be used to leave a Finally block."
+			Else If TContinueStmt(stmt) Then
+				Local loop:TLoopStmt
+				If TLoopLabelExpr(TContinueStmt(stmt).label) Then
+					loop = TLoopLabelExpr(TContinueStmt(stmt).label).loop
+				Else
+					loop = TLoopStmt(Self.FindLoop())
+				End If
+				Local f:TBlockDecl = SurroundingFinallyBlock(Self)
+				If f And f <> SurroundingFinallyBlock(loop.block) Then PushErr stmt.errInfo; Err "Continue cannot be used to leave a Finally block."
+			End If
+			
+			Function SurroundingFinallyBlock:TBlockDecl(block:TBlockDecl)
+				' get the innermost Finally block surrounding the current statement
+				While block And Not TFuncDecl(block)
+					If block.isFinallyBlock Then Return block
+					block = TBlockDecl(block.scope)
+				Wend
+				Return Null
+			End Function
 		Next
 		PopEnv
 	End Method
@@ -3157,7 +3189,7 @@ End Rem
 	
 End Type
 
-Type TLoopLabelDecl Extends TDecl
+Type TLoopLabelDecl Extends TDecl ' also used internally for Try constructs
 
 	Field realIdent:String
 

+ 14 - 6
parser.bmx

@@ -2039,10 +2039,12 @@ End Rem
 
 		Local block:TBlockDecl=New TBlockDecl.Create( tryStmtDecl )
 		Local catches:TList=New TList
+		Local finallyStmt:TFinallyStmt = Null
 
 		PushBlock block
 		While _toke<>"end" And _toke<>"endtry"
 			If CParse( "catch" )
+				If finallyStmt Then Err "'Catch' can not appear after 'Finally'."
 				Local id:String=ParseIdent()
 				Local ty:TType
 				If Not CParse(":") Then
@@ -2059,6 +2061,12 @@ End Rem
 				catches.AddLast(New TCatchStmt.Create( init,block ))
 				PopBlock
 				PushBlock block
+			Else If CParse("finally") Then
+				If finallyStmt Then Err "Try statement cannot have more than one Finally block."
+				Local block:TBlockDecl = New TBlockDecl.Create(_block, , True)
+				finallyStmt = New TFinallyStmt.Create(block)
+				PopBlock
+				PushBlock block
 			Else
 				ParseStmt
 
@@ -2075,18 +2083,18 @@ End Rem
 			End If
 		Wend
 
+		If catches.Count() = 0 And Not finallyStmt Then Err "Expecting 'Catch' or 'Finally'."
+		
 		PopBlock ' try block
 		
 		If Not CParse("endtry") Then
-			' TODO : handle case of no catch - perhaps throw the exception again.
-			'If Not catches.Length() Err "Try block must have at least one catch block"
 			NextToke
 			CParse "try"
 		End If
 
 		PopBlock ' tryStmtDecl
 		
-		Local tryStmt:TTryStmt = New TTryStmt.Create( block,TCatchStmt[](catches.ToArray()) )
+		Local tryStmt:TTryStmt = New TTryStmt.Create(block,TCatchStmt[](catches.ToArray()), finallyStmt)
 
 		tryStmtDecl.tryStmt = tryStmt
 
@@ -2193,9 +2201,9 @@ End Rem
 				SetErr
 				Select _toke
 				Case "case"
-					Err "Case can not appear after default."
+					Err "Case can not appear after Default."
 				Case "default"
-					Err "Select statement can have only one default block."
+					Err "Select statement can have only one Default block."
 				End Select
 				ParseStmt
 
@@ -4060,7 +4068,7 @@ End Rem
 			con = 0
 			Try
 				If Eval( toker,New TIntType ) = "1" con = 1
-			Catch error:String
+			Catch Error:String
 				con = 0
 			End Try
 

+ 45 - 12
stmt.bmx

@@ -22,7 +22,7 @@
 '    distribution.
 '
 
-Type TStmt
+Type TStmt Abstract
 	Field errInfo$
 	' whether this statement was generated by the compiler or not
 	Field generated:Int
@@ -272,19 +272,27 @@ Type TTryStmt Extends TStmt
 
 	Field block:TBlockDecl
 	Field catches:TCatchStmt[]
+	Field finallyStmt:TFinallyStmt
+	Field rethrowLabel:TLoopLabelDecl
+	Field endTryLabel:TLoopLabelDecl
 	
-	Method Create:TTryStmt( block:TBlockDecl,catches:TCatchStmt[] )
+	Method Create:TTryStmt( block:TBlockDecl,catches:TCatchStmt[],finallyStmt:TFinallyStmt )
 		Self.block=block
 		Self.catches=catches
+		Self.finallyStmt=finallyStmt
+		Self.rethrowLabel = New TLoopLabelDecl.Create("rethrow")
+		Self.endTryLabel  = New TLoopLabelDecl.Create("endtry")
 		Return Self
 	End Method
 	
 	Method OnCopy:TStmt( scope:TScopeDecl )
-		Local tcatches:TCatchStmt[] = Self.catches[..]
-		For Local i:Int=0 Until tcatches.Length
-			tcatches[i]=TCatchStmt( tcatches[i].Copy( scope ) )
+		Local catchCopies:TCatchStmt[] = Self.catches[..]
+		For Local i:Int = 0 Until catchCopies.Length
+			catchCopies[i] = TCatchStmt(catchCopies[i].Copy(scope))
 		Next
-		Return New TTryStmt.Create( block.CopyBlock( scope ),tcatches )
+		Local finallyCopy:TFinallyStmt = Null
+		If finallyStmt Then finallyCopy = TFinallyStmt(finallyStmt.Copy(scope))
+		Return New TTryStmt.Create(block.CopyBlock(scope), catchCopies, finallyCopy)
 	End Method
 	
 	Method OnSemant()
@@ -307,6 +315,7 @@ Type TTryStmt Extends TStmt
 				EndIf
 			Next
 		Next
+		If finallyStmt Then finallyStmt.Semant
 	End Method
 	
 	Method Trans$()
@@ -342,6 +351,31 @@ Type TCatchStmt Extends TStmt
 
 End Type
 
+Type TFinallyStmt Extends TStmt
+
+	Field block:TBlockDecl
+	Field finallyLabel:TLoopLabelDecl
+	Field returnLabelPtrDecl:TLocalDecl
+	
+	Method Create:TFinallyStmt( block:TBlockDecl )
+		Self.block=block
+		Self.finallyLabel = New TLoopLabelDecl.Create("finally")
+		Return Self
+	End Method
+
+	Method OnCopy:TStmt( scope:TScopeDecl )
+		Return New TFinallyStmt.Create( block.CopyBlock( scope ) )
+	End Method
+	
+	Method OnSemant()
+		block.Semant
+	End Method
+	
+	Method Trans$()
+	End Method
+
+End Type
+
 Type TThrowStmt Extends TStmt
 	Field expr:TExpr
 
@@ -365,10 +399,12 @@ Type TThrowStmt Extends TStmt
 	End Method
 End Type
 
-Type TBreakStmt Extends TStmt
-
+Type TLoopControlStmt Extends TStmt Abstract
 	Field loop:TLoopStmt
 	Field label:TExpr
+End Type
+
+Type TBreakStmt Extends TLoopControlStmt
 
 	Method Create:TBreakStmt( label:TExpr )
 		Self.label=label
@@ -400,10 +436,7 @@ Type TBreakStmt Extends TStmt
 	
 End Type
 
-Type TContinueStmt Extends TStmt
-
-	Field loop:TLoopStmt
-	Field label:TExpr
+Type TContinueStmt Extends TLoopControlStmt
 	
 	Method Create:TContinueStmt( label:TExpr, generated:Int = False )
 		Self.label=label

+ 43 - 7
tests/framework/language/try_01.bmx

@@ -1,12 +1,48 @@
-Rem
-	This test checks:
-	- if try without "catch" is possible
-End Rem
+' Tests whether exceptions are caught correctly in simple Try-Catch constructs.
+
 SuperStrict
+Framework BRL.StandardIO
+
+
+Print; Print 1
+Try
+	Print "try"
+Catch e:String
+	Print "catch " + e
+End Try
+
 
-Import BRL.StandardIO
+Print; Print 2
+Try
+	Print "try"
+	Throw "ex"
+Catch e:String
+	Print "catch " + e
+End Try
 
 
+Print; Print 3
 Try
-	print "should get printed"
-End Try
+	Try
+		Print "try"
+		Throw "ex"
+	Catch e:String
+		Print "catch " + e
+	End Try
+Catch e:String
+	Print "catch2 " + e
+End Try
+
+
+Print; Print 4
+Try
+	Try
+		Print "try"
+		Throw "ex"
+	Catch e:TStream
+		Print "this should not happen"
+	End Try
+Catch e:String
+	Print "catch2 " + e
+End Try
+

+ 15 - 0
tests/framework/language/try_01.res

@@ -0,0 +1,15 @@
+
+1
+try
+
+2
+try
+catch ex
+
+3
+try
+catch ex
+
+4
+try
+catch2 ex

+ 47 - 0
tests/framework/language/try_02.bmx

@@ -0,0 +1,47 @@
+' Tests whether Finally blocks are executed correctly in simple Try-Finally constructs.
+
+SuperStrict
+Framework BRL.StandardIO
+
+
+Print; Print 1
+Try
+	Print "try"
+Finally
+	Print "finally"
+End Try
+
+
+Print; Print 2
+F
+Function F()
+	Try
+		Print "try"
+		Return
+	Finally
+		Print "finally"
+	End Try
+End Function
+
+
+Print; Print 3
+For Local i:Int = 1 To 2
+	Try
+		Print "try"
+		Exit
+	Finally
+		Print "finally"
+	End Try
+Next
+
+
+Print; Print 4
+For Local i:Int = 1 To 2
+	Try
+		Print "try"
+		Continue
+	Finally
+		Print "finally"
+	End Try
+Next
+

+ 18 - 0
tests/framework/language/try_02.res

@@ -0,0 +1,18 @@
+
+1
+try
+finally
+
+2
+try
+finally
+
+3
+try
+finally
+
+4
+try
+finally
+try
+finally

+ 69 - 0
tests/framework/language/try_03.bmx

@@ -0,0 +1,69 @@
+' Tests whether exceptions are caught and Finally blocks are executed correctly in simple Try-Catch-Finally constructs.
+
+SuperStrict
+Framework BRL.StandardIO
+
+
+Print; Print 1
+Try
+	Print "try"
+Catch e:String
+	Print "catch " + e
+Finally
+	Print "finally"
+End Try
+
+
+Print; Print 2
+Try
+	Print "try"
+	Throw "ex"
+Catch e:String
+	Print "catch " + e
+Finally
+	Print "finally"
+End Try
+
+
+Print; Print 3
+Try
+	Try
+		Print "try"
+		Throw "ex"
+	Finally
+		Print "finally"
+	End Try
+Catch e:String
+	Print "catch2 " + e
+End Try
+
+
+Print; Print 4
+Try
+	Try
+		Print "try"
+		Throw "ex"
+	Catch e:TStream
+		Print "this should not happen"
+	Finally
+		Print "finally"
+	End Try
+Catch e:String
+	Print "catch2 " + e
+End Try
+
+Print; Print 5
+Try
+	Try
+		Print "try"
+		Throw "ex"
+	Catch e:String
+		Print "catch " + e
+		Throw "ex2"
+	Finally
+		Print "finally"
+	End Try
+Catch e:String
+	Print "catch2 " + e
+End Try
+

+ 25 - 0
tests/framework/language/try_03.res

@@ -0,0 +1,25 @@
+
+1
+try
+finally
+
+2
+try
+catch ex
+finally
+
+3
+try
+finally
+catch2 ex
+
+4
+try
+finally
+catch2 ex
+
+5
+try
+catch ex
+finally
+catch2 ex2

+ 265 - 0
tests/framework/language/try_04.bmx

@@ -0,0 +1,265 @@
+' Tests whether exceptions are caught and Finally blocks are executed correctly in complex Try-Catch-Finally constructs.
+
+SuperStrict
+Framework BRL.StandardIO
+
+
+Function GetNumber:Int()
+	Print "getting 5"
+	Return 5
+End Function
+
+Function ThrowEx:Int()
+	Print "throw ex"
+	Throw "ex"
+End Function
+
+Function ThrowEx2:Int()
+	Print "throw ex2"
+	Throw "ex2"
+End Function
+
+
+Print; Print 1
+Print "returned " + F()
+Function F:Int()
+	Try
+		Print "try"
+		Return GetNumber()
+	Finally
+		Print "finally"
+	End Try
+End Function
+
+
+Print; Print 2
+Print "returned " + F2()
+Function F2:Int()
+	Try
+		Print "try"
+		Return GetNumber()
+	Catch e:Int[]
+		Print "this should not happen"
+	Catch e:String
+		Print "this should not happen"
+	Finally
+		Print "finally"
+	End Try
+End Function
+
+
+Print; Print 3
+Print "returned " + F3()
+Function F3:Int()
+	Try
+		Print "try"
+		Return ThrowEx()
+	Catch e:Int[]
+		Print "this should not happen"
+	Catch e:String
+		Print "catch " + e
+	Finally
+		Print "finally"
+	End Try
+End Function
+
+
+Print; Print 4
+Print "returned " + F4()
+Function F4:Int()
+	Try
+		Print "try"
+		Return ThrowEx()
+	Catch e:Int[]
+		Print "this should not happen"
+	Catch e:String
+		Print "catch " + e
+		Return 7
+	Finally
+		Print "finally"
+	End Try
+End Function
+
+
+Print; Print 5
+Print "returned " + F5()
+Function F5:Int()
+	Try
+		Try
+			Print "try"
+			Return ThrowEx()
+		Catch e:Int[]
+			Print "this should not happen"
+		Catch e:String
+			Print "catch " + e
+			Return ThrowEx2()
+		Finally
+			Print "finally"
+		End Try
+	Catch e:String
+		Print "catch2 " + e
+	Finally
+		Print "finally2"
+	End Try
+End Function
+
+
+Print; Print 6
+Try
+	F6
+Catch e:String
+	Print "catch3 " + e
+End Try
+Function F6()
+	For Local i:Int = 1 To 2
+		Try
+			Print "try"
+			Return
+		Finally
+			Print "finally"
+			Try
+				Print "try2"
+				Throw "asdf"
+			Finally
+				Print "finally2"
+			End Try
+		End Try
+	Next
+End Function
+
+
+Print; Print 7
+F7
+Function F7()
+	For Local i:Int = 1 To 2
+		Try
+			Print "try"
+			Try
+				Print "try2"
+				Exit
+			Finally
+				Print "finally2"
+			End Try
+		Finally
+			Print "finally"
+		End Try
+	Next
+End Function
+
+
+Print; Print 8
+F8
+Function F8()
+	For Local i:Int = 1 To 2
+		Try
+			Print "try"
+			Try
+				Print "try2"
+				Continue
+			Finally
+				Print "finally2"
+			End Try
+		Finally
+			Print "finally"
+		End Try
+	Next
+End Function
+
+
+Print; Print 9
+F9
+Function F9()
+	#loop
+	For Local i:Int = 1 To 2
+		Try
+			Print "try"
+			Try
+				Print "try2"
+				For Local j:Int = 1 To 2
+					Exit loop
+				Next
+			Finally
+				Print "finally2"
+			End Try
+		Finally
+			Print "finally"
+		End Try
+	Next
+End Function
+
+
+Print; Print 10
+F10
+Function F10()
+	#loop
+	For Local i:Int = 1 To 2
+		Try
+			Print "try"
+			Try
+				Print "try2"
+				For Local j:Int = 1 To 2
+					Continue loop
+				Next
+			Finally
+				Print "finally2"
+			End Try
+		Finally
+			Print "finally"
+		End Try
+	Next
+End Function
+
+
+Print; Print 11
+Try
+	Print "try"
+	Try
+		Print "try2"
+		Throw "ex"
+	Catch e:String
+		Print "catch2 " + e
+		Throw "ex2"
+	Finally
+		Print "finally2"
+		Try
+			Print "try3"
+		Catch e:String
+			Print "catch3"
+		Finally
+			Print "finally3"
+			Throw "ex3"
+		End Try
+	End Try
+Catch e:String
+	Print "catch " + e
+End Try
+
+
+Print; Print 12
+Try
+	Print "returned " + F12()
+Catch e:String
+	Print "catch5 " + e
+End Try
+Function F12:Int()
+	Try
+		Try
+			Try
+				Try
+					Print "try4"
+					Return 7
+				Finally
+					Print "finally4"
+				End Try
+			Finally
+				Print "finally3"
+			End Try
+		Finally
+			Print "finally2"
+			Throw "ex"
+		End Try
+	Finally
+		Print "finally"
+	End Try
+	Return 2
+End Function

+ 92 - 0
tests/framework/language/try_04.res

@@ -0,0 +1,92 @@
+
+1
+try
+getting 5
+finally
+returned 5
+
+2
+try
+getting 5
+finally
+returned 5
+
+3
+try
+throw ex
+catch ex
+finally
+returned 0
+
+4
+try
+throw ex
+catch ex
+finally
+returned 7
+
+5
+try
+throw ex
+catch ex
+throw ex2
+finally
+catch2 ex2
+finally2
+returned 0
+
+6
+try
+finally
+try2
+finally2
+catch3 asdf
+
+7
+try
+try2
+finally2
+finally
+
+8
+try
+try2
+finally2
+finally
+try
+try2
+finally2
+finally
+
+9
+try
+try2
+finally2
+finally
+
+10
+try
+try2
+finally2
+finally
+try
+try2
+finally2
+finally
+
+11
+try
+try2
+catch2 ex
+finally2
+try3
+finally3
+catch ex3
+
+12
+try4
+finally4
+finally3
+finally2
+finally
+catch5 ex

+ 1 - 1
toker.bmx

@@ -47,7 +47,7 @@ Type TToker
 		"mod,continue,exit,include,import,module,extern,framework,new,self,super,eachin,true,false," + ..
 		"null,not,extends,abstract,select,case,default,const,local,global,field,method,function,type," + ..
 		"and,or,shl,shr,sar,end,if,then,else,elseif,endif,while,wend,repeat,until,forever,for,to,step," + ..
-		"next,return,alias,rem,endrem,throw,assert,try,catch,nodebug,incbin,endselect,endmethod," + ..
+		"next,return,alias,rem,endrem,throw,assert,try,catch,finally,nodebug,incbin,endselect,endmethod," + ..
 		"endfunction,endtype,endextern,endtry,endwhile,pi,release,defdata,readdata,restoredata,interface," + ..
 		"endinterface,implements,size_t,uint,ulong,struct,endstruct,operator,where"
 	Global _keywords:TMap

+ 1908 - 1858
translator.bmx

@@ -1,1863 +1,1913 @@
 ' Copyright (c) 2013-2018 Bruce A Henderson
-'
-' Based on the public domain Monkey "trans" by Mark Sibly
-'
-' This software is provided 'as-is', without any express or implied
-' warranty. In no event will the authors be held liable for any damages
-' arising from the use of this software.
-'
-' Permission is granted to anyone to use this software for any purpose,
-' including commercial applications, and to alter it and redistribute it
-' freely, subject to the following restrictions:
-'
-'    1. The origin of this software must not be misrepresented; you must not
-'    claim that you wrote the original software. If you use this software
-'    in a product, an acknowledgment in the product documentation would be
-'    appreciated but is not required.
-'
-'    2. Altered source versions must be plainly marked as such, and must not be
-'    misrepresented as being the original software.
-'
-'    3. This notice may not be removed or altered from any source
-'    distribution.
-'
-
-Global _trans:TTranslator
-
-Type TTranslator
-
-	Field _app:TAppDecl
-
-	Field outputFiles:TMap = New TMap
-
-	Field indent$
-	Field LINES:TStringList'=New TStringList
-	Field unreachable:Int,broken:Int
-	
-	Field contLabelId:Int
-	Field exitLabelId:Int
-	
-	'Munging needs a big cleanup!
-	
-	Field mungScope:TMap=New TMap'<TDecl>
-	Field mungStack:TStack=New TStack'< StringMap<TDecl> >
-	Field funcMungs:TMap=New TMap'<FuncDeclList>
-	Field customVarStack:TStack = New TStack
-	Field varStack:TStack = New TStack
-
-	Field tryStack:TStack = New TStack
-	Field loopTryStack:TStack = New TStack
-
-	Field mungedScopes:TMap=New TMap'<StringSet>
-	'Field funcMungs:TFuncDeclList=New TFuncDeclList
-	'Field mungedFuncs:TMap=New Map
-	Field localScopeStack:TStack = New TStack
-	Field localScope:TStack = New TStack
-	Field ind:Int
-	Field debugOut:String
-	
-	Field processingReturnStatement:Int
-
-	Method PushVarScope()
-		varStack.Push customVarStack
-		customVarStack = New TStack
-	End Method
-	
-	Method PopVarScope()
-		customVarStack=TStack(varStack.Pop())
-	End Method
-	
-	Method PushLoopLocalStack(stmt:Object)
-		ind :+ 1
-		If DEBUG Then
-			Emit "// --> STACK = " + ind
-		End If
-		localScope.Push stmt
-	End Method
-
-	Method PopLoopLocalStack()
-		If DEBUG Then
-			Emit "// <-- STACK = " + ind
-		End If
-		ind :- 1
-		If ind < 0 Then
-			InternalErr
-		End If
-		localScope.Pop
-	End Method
-
-	Method LoopLocalScopeDepth:Int(findStmt:TStmt)
-		Local count:Int = 0
-
-		For Local stmt:Object = EachIn localScope
-			If TBlockDecl(stmt) = Null Then
-				If findStmt And TTryBreakCheck(stmt) And findStmt <> TTryBreakCheck(stmt).stmt Then
-					Continue
-				End If
-				Exit
-			End If
-
-			count :+ 1
-		Next
-		
-		Return count
-	End Method
-
-	Method GetTopLocalLoop:TTryBreakCheck(findStmt:TStmt)
-		For Local tbc:TTryBreakCheck = EachIn localScope
-			If findStmt And findStmt <> tbc.stmt Then
-				Continue
-			End If
-			Return tbc
-		Next
-	End Method
-
-	Method PushLoopTryStack(stmt:Object)
-		If loopTryStack.Length() = 0 Then
-			' Try statements can only be applied here to loops
-			If TTryStmt(stmt) = Null Then
-				loopTryStack.Push stmt
-			End If
-		Else
-			loopTryStack.Push stmt
-		End If
-	End Method
-
-	Method PopLoopTryStack()
-		loopTryStack.Pop
-	End Method
-	
-	Method LoopTryDepth:Int(findStmt:TStmt)
-		Local count:Int = 0
-		
-		For Local stmt:Object = EachIn loopTryStack
-			If TTryStmt(stmt) = Null Then
-				If findStmt And findStmt <> stmt Then
-					Continue
-				End If
-				
-				Exit
-			End If
-
-			count :+ 1
-		Next
-		
-		Return count
-	End Method
-
-	Method GetTopLoop:TTryBreakCheck(findStmt:TStmt)
-		For Local tbc:TTryBreakCheck = EachIn loopTryStack
-			If findStmt And findStmt <> tbc.stmt Then
-				Continue
-			End If
-			Return tbc
-		Next
-	End Method
-
-	Method TransManglePointer$( ty:TType )
-		Local p:String
-		
-		If ty
-
-			If ty._flags & TType.T_VAR Then
-				p:+ "v"
-			End If
-
-			If ty._flags & TType.T_PTR Then
-				p:+ "p"
-			Else If ty._flags & TType.T_PTRPTR Then
-				p:+ "pp"
-			Else If ty._flags & TType.T_PTRPTRPTR Then
-				p:+ "ppp"
-			End If
-
-		End If
-		
-		Return p
-	End Method
-
-	Method TransMangleType:String(ty:TType)
-		Local p:String = TransManglePointer(ty)
-
-		If TVoidType( ty ) Return "v"
-		If TByteType( ty ) Return p + "b"
-		If TShortType( ty ) Return p + "s"
-		If TIntType( ty ) Return p + "i"
-		If TUIntType( ty ) Return p + "u"
-		If TFloatType( ty ) Return p + "f"
-		If TDoubleType( ty ) Return p + "d"
-		If TLongType( ty ) Return p + "l"
-		If TULongType( ty ) Return p + "y"
-		If TSizeTType( ty ) Return p + "z"
-		If TFloat64Type( ty ) Return p + "h"
-		If TFloat128Type( ty ) Return p + "k"
-		If TInt128Type( ty ) Return p + "j"
-		If TDouble128Type( ty ) Return p + "m"
-		If TStringType( ty ) Return p + "S"
-		If TWParamType( ty ) Return p + "W"
-		If TLParamType( ty ) Return p + "L"
-		If TArrayType( ty ) Then
-			Return p + "a" + TransMangleType(TArrayType( ty ).elemType)
-		End If
-		If TObjectType( ty ) Then
-			If Not TObjectType( ty ).classdecl.IsExtern()
-				Return p + "T" + TObjectType( ty ).classDecl.ident
-			Else
-				If TObjectType( ty ).classdecl.IsInterface() Then
-					Return p + "I" + TObjectType(ty).classDecl.ident
-				ElseIf TObjectType( ty ).classdecl.IsStruct() Then
-					Return p + "R" + TObjectType(ty).classDecl.ident
-				Else
-					Return p + "E" + TObjectType(ty).classDecl.ident
-				End If
-			End If
-		End If
-		If TFunctionPtrType( ty ) Then
-			Local func:TFuncDecl = TFunctionPtrType( ty ).func
-			Local s:String = "F" + MangleMethodArgs(func)
-'			For Local i:Int = 0 Until func.argDecls.length
-'				s :+ TransMangleType(func.argDecls[i].ty)
-'			Next
-			Return s + "_" + TransMangleType(func.retType) + "_"
-		End If
-		
-		Err "Unsupported type for name mangling : " + ty.ToString()
-	End Method
-
-	Method MangleMethod:String(fdecl:TFuncDecl)
-		If (fdecl.IsMethod() And Not fdecl.ClassScope().IsStruct())Or fdecl.IsCtor() Then
-			Return MangleMethodArgs(fdecl)
-		Else
-			Return MangleMethodRetType(fdecl) + MangleMethodArgs(fdecl)
-		End If
-	End Method
-	
-	Method MangleMethodRetType:String(fdecl:TFuncDecl)
-		If fdecl.retType Then
-			Return "_" + TransMangleType(fdecl.retType)
-		Else
-			Return "_v"
-		End If
-	End Method
-	
-	Method MangleMethodArgs:String(fdecl:TFuncDecl)
-		Local s:String
-		For Local arg:TArgDecl = EachIn fdecl.argDecls
-			If Not s Then
-				s = "_"
-			End If
-			s :+ TransMangleType(arg.ty)
-		Next
-		Return s
-	End Method
-
-	Method equalsTorFunc:Int(classDecl:TClassDecl, func:TFuncDecl)
-		If func.IdentLower() = "new" Or func.IdentLower() = "delete" Then
-			Return True
-		End If
-		Return False
-	End Method
-
-	Method equalsBuiltInFunc:Int(classDecl:TClassDecl, func:TFuncDecl, checked:Int = False)
-		If func.equalsBuiltIn > -1 Then
-			Return func.equalsBuiltIn
-		End If
-	
-		If checked Or func.IdentLower() = "tostring" Or func.IdentLower() = "compare" Or func.IdentLower() = "sendmessage" Or func.IdentLower() = "new" Or func.IdentLower() = "delete" Then
-			If classDecl.munged = "bbObjectClass" Then
-				For Local decl:TFuncDecl = EachIn classDecl.Decls()
-					If Not decl.IsSemanted() Then
-						decl.Semant
-					End If
-					If decl.IdentLower() = func.IdentLower() Then
-						Local res:Int = decl.EqualsFunc(func)
-						If res Then
-							func.equalsBuiltIn = True
-						End If
-						Return res
-					End If
-				Next
-			End If
-			If classDecl.superClass Then
-				Return equalsBuiltInFunc(classDecl.superClass, func, True)
-			End If
-		End If
-		func.equalsBuiltIn = False
-		Return False
-	End Method
-
-	Method equalsIfcBuiltInFunc:Int(classDecl:TClassDecl, func:TFuncDecl, checked:Int = False)
-		If checked Or func.IdentLower() = "new" Or func.IdentLower() = "delete" Then
-			If classDecl.munged = "bbObjectClass" Then
-				For Local decl:TFuncDecl = EachIn classDecl.Decls()
-					If Not decl.IsSemanted() Then
-						decl.Semant
-					End If
-					If decl.IdentLower() = func.IdentLower() Then
-						Return decl.EqualsFunc(func)
-					End If
-				Next
-			End If
-			If classDecl.superClass Then
-				Return equalsIfcBuiltInFunc(classDecl.superClass, func, True)
-			End If
-		End If
-		Return False
-	End Method
-
-	Method MungFuncDecl( fdecl:TFuncDecl )
-
-		If fdecl.munged Return
-		
-		Local funcs:TFuncDeclList=TFuncDeclList(funcMungs.ValueForKey( fdecl.ident ))
-		If funcs
-			For Local tdecl:TFuncDecl=EachIn funcs
-				If fdecl.EqualsArgs( tdecl ) And fdecl.scope = tdecl.scope
-					fdecl.munged=tdecl.munged
-					Return
-				EndIf
-			Next
-		Else
-			funcs=New TFuncDeclList
-			funcMungs.Insert fdecl.ident,funcs
-		EndIf
-
-		If fdecl.scope Then
-			Local id:String = fdecl.ident
-
-			If fdecl.attrs & FUNC_OPERATOR Then
-				id = MungSymbol(id)
-			End If
-			
-			fdecl.munged = fdecl.ParentScope().munged + "_" + id
-			
-			If Not equalsBuiltInFunc(fdecl.classScope(), fdecl) And Not fdecl.noMangle Then
-				fdecl.munged :+ MangleMethod(fdecl)
-			End If
-			
-			' fields are lowercase with underscore prefix.
-			' a function pointer with FUNC_METHOD is a field function pointer.
-			'If TFieldDecl(fdecl) Or (TFuncDecl(decl) And (decl.attrs & FUNC_METHOD) And (decl.attrs & FUNC_PTR)) Then
-			'	munged = "_" + munged.ToLower()
-			'End If
-		Else
-			fdecl.munged="bb_"+fdecl.ident
-		End If
-		
-		funcs.AddLast fdecl
-	End Method
-	
-	Method MungSymbol:String(sym:String)
-		Select sym
-			Case "*"
-				Return "_mul"
-			Case "/"
-				Return "_div"
-			Case "+"
-				Return "_add"
-			Case "-"
-				Return "_sub"
-			Case "&"
-				Return "_and"
-			Case "|"
-				Return "_or"
-			Case "~~"
-				Return "_xor"
+'
+' Based on the public domain Monkey "trans" by Mark Sibly
+'
+' This software is provided 'as-is', without any express or implied
+' warranty. In no event will the authors be held liable for any damages
+' arising from the use of this software.
+'
+' Permission is granted to anyone to use this software for any purpose,
+' including commercial applications, and to alter it and redistribute it
+' freely, subject to the following restrictions:
+'
+'    1. The origin of this software must not be misrepresented; you must not
+'    claim that you wrote the original software. If you use this software
+'    in a product, an acknowledgment in the product documentation would be
+'    appreciated but is not required.
+'
+'    2. Altered source versions must be plainly marked as such, and must not be
+'    misrepresented as being the original software.
+'
+'    3. This notice may not be removed or altered from any source
+'    distribution.
+'
+
+Global _trans:TTranslator
+
+Type TTranslator
+
+	Field _app:TAppDecl
+
+	Field outputFiles:TMap = New TMap
+
+	Field indent$
+	Field LINES:TStringList'=New TStringList
+	Field unreachable:Int,broken:Int
+	
+	Field contLabelId:Int
+	Field exitLabelId:Int
+	
+	'Munging needs a big cleanup!
+	
+	Field mungScope:TMap=New TMap'<TDecl>
+	Field mungStack:TStack=New TStack'< StringMap<TDecl> >
+	Field funcMungs:TMap=New TMap'<FuncDeclList>
+	Field customVarStack:TStack = New TStack
+	Field varStack:TStack = New TStack
+
+	Field tryStack:TStack = New TStack
+	Field loopTryStack:TStack = New TStack
+
+	Field mungedScopes:TMap=New TMap'<StringSet>
+	'Field funcMungs:TFuncDeclList=New TFuncDeclList
+	'Field mungedFuncs:TMap=New Map
+	Field localScopeStack:TStack = New TStack
+	Field localScope:TStack = New TStack
+	Field ind:Int
+	Field debugOut:String
+	
+	Field processingReturnStatement:Int
+
+	Method PushVarScope()
+		varStack.Push customVarStack
+		customVarStack = New TStack
+	End Method
+	
+	Method PopVarScope()
+		customVarStack=TStack(varStack.Pop())
+	End Method
+	
+	Method PushLoopLocalStack(stmt:Object)
+		ind :+ 1
+		If DEBUG Then
+			Emit "// --> STACK = " + ind
+		End If
+		localScope.Push stmt
+	End Method
+
+	Method PopLoopLocalStack()
+		If DEBUG Then
+			Emit "// <-- STACK = " + ind
+		End If
+		ind :- 1
+		If ind < 0 Then
+			InternalErr
+		End If
+		localScope.Pop
+	End Method
+
+	Method LoopLocalScopeDepth:Int(findStmt:TStmt)
+		Local count:Int = 0
+
+		For Local stmt:Object = EachIn localScope
+			If TBlockDecl(stmt) = Null Then
+				If findStmt And TTryBreakCheck(stmt) And findStmt <> TTryBreakCheck(stmt).stmt Then
+					Continue
+				End If
+				Exit
+			End If
+
+			count :+ 1
+		Next
+		
+		Return count
+	End Method
+
+	Method GetTopLocalLoop:TTryBreakCheck(findStmt:TStmt)
+		For Local tbc:TTryBreakCheck = EachIn localScope
+			If findStmt And findStmt <> tbc.stmt Then
+				Continue
+			End If
+			Return tbc
+		Next
+	End Method
+
+	Method PushLoopTryStack(stmt:Object)
+		If loopTryStack.Length() = 0 Then
+			' Try statements can only be applied here to loops
+			If TTryStmt(stmt) = Null Then
+				loopTryStack.Push stmt
+			End If
+		Else
+			loopTryStack.Push stmt
+		End If
+	End Method
+
+	Method PopLoopTryStack()
+		loopTryStack.Pop
+	End Method
+	
+	Method LoopTryDepth:Int(findStmt:TStmt)
+		Local count:Int = 0
+		
+		For Local stmt:Object = EachIn loopTryStack
+			If TTryStmt(stmt) = Null Then
+				If findStmt And findStmt <> stmt Then
+					Continue
+				End If
+				
+				Exit
+			End If
+			count :+ 1
+		Next
+		
+		Return count
+	End Method
+
+	Method LoopTryStmts:TTryStmt[](findStmt:TStmt)
+		Local stmts:TTryStmt[]
+		
+		For Local stmt:Object = EachIn loopTryStack
+			If TTryStmt(stmt) Then
+				stmts :+ [TTryStmt(stmt)]
+			Else
+				If findStmt And findStmt <> stmt Then
+					Continue
+				End If
+				
+				Exit
+			End If
+		Next
+		
+		Return stmts
+	End Method
+	
+	Method GetTopLoop:TTryBreakCheck(findStmt:TStmt)
+		For Local tbc:TTryBreakCheck = EachIn loopTryStack
+			If findStmt And findStmt <> tbc.stmt Then
+				Continue
+			End If
+			Return tbc
+		Next
+	End Method
+
+	Method TransManglePointer$( ty:TType )
+		Local p:String
+		
+		If ty
+
+			If ty._flags & TType.T_VAR Then
+				p:+ "v"
+			End If
+
+			If ty._flags & TType.T_PTR Then
+				p:+ "p"
+			Else If ty._flags & TType.T_PTRPTR Then
+				p:+ "pp"
+			Else If ty._flags & TType.T_PTRPTRPTR Then
+				p:+ "ppp"
+			End If
+
+		End If
+		
+		Return p
+	End Method
+
+	Method TransMangleType:String(ty:TType)
+		Local p:String = TransManglePointer(ty)
+
+		If TVoidType( ty ) Return "v"
+		If TByteType( ty ) Return p + "b"
+		If TShortType( ty ) Return p + "s"
+		If TIntType( ty ) Return p + "i"
+		If TUIntType( ty ) Return p + "u"
+		If TFloatType( ty ) Return p + "f"
+		If TDoubleType( ty ) Return p + "d"
+		If TLongType( ty ) Return p + "l"
+		If TULongType( ty ) Return p + "y"
+		If TSizeTType( ty ) Return p + "z"
+		If TFloat64Type( ty ) Return p + "h"
+		If TFloat128Type( ty ) Return p + "k"
+		If TInt128Type( ty ) Return p + "j"
+		If TDouble128Type( ty ) Return p + "m"
+		If TStringType( ty ) Return p + "S"
+		If TWParamType( ty ) Return p + "W"
+		If TLParamType( ty ) Return p + "L"
+		If TArrayType( ty ) Then
+			Return p + "a" + TransMangleType(TArrayType( ty ).elemType)
+		End If
+		If TObjectType( ty ) Then
+			If Not TObjectType( ty ).classdecl.IsExtern()
+				Return p + "T" + TObjectType( ty ).classDecl.ident
+			Else
+				If TObjectType( ty ).classdecl.IsInterface() Then
+					Return p + "I" + TObjectType(ty).classDecl.ident
+				ElseIf TObjectType( ty ).classdecl.IsStruct() Then
+					Return p + "R" + TObjectType(ty).classDecl.ident
+				Else
+					Return p + "E" + TObjectType(ty).classDecl.ident
+				End If
+			End If
+		End If
+		If TFunctionPtrType( ty ) Then
+			Local func:TFuncDecl = TFunctionPtrType( ty ).func
+			Local s:String = "F" + MangleMethodArgs(func)
+'			For Local i:Int = 0 Until func.argDecls.length
+'				s :+ TransMangleType(func.argDecls[i].ty)
+'			Next
+			Return s + "_" + TransMangleType(func.retType) + "_"
+		End If
+		
+		Err "Unsupported type for name mangling : " + ty.ToString()
+	End Method
+
+	Method MangleMethod:String(fdecl:TFuncDecl)
+		If (fdecl.IsMethod() And Not fdecl.ClassScope().IsStruct())Or fdecl.IsCtor() Then
+			Return MangleMethodArgs(fdecl)
+		Else
+			Return MangleMethodRetType(fdecl) + MangleMethodArgs(fdecl)
+		End If
+	End Method
+	
+	Method MangleMethodRetType:String(fdecl:TFuncDecl)
+		If fdecl.retType Then
+			Return "_" + TransMangleType(fdecl.retType)
+		Else
+			Return "_v"
+		End If
+	End Method
+	
+	Method MangleMethodArgs:String(fdecl:TFuncDecl)
+		Local s:String
+		For Local arg:TArgDecl = EachIn fdecl.argDecls
+			If Not s Then
+				s = "_"
+			End If
+			s :+ TransMangleType(arg.ty)
+		Next
+		Return s
+	End Method
+
+	Method equalsTorFunc:Int(classDecl:TClassDecl, func:TFuncDecl)
+		If func.IdentLower() = "new" Or func.IdentLower() = "delete" Then
+			Return True
+		End If
+		Return False
+	End Method
+
+	Method equalsBuiltInFunc:Int(classDecl:TClassDecl, func:TFuncDecl, checked:Int = False)
+		If func.equalsBuiltIn > -1 Then
+			Return func.equalsBuiltIn
+		End If
+	
+		If checked Or func.IdentLower() = "tostring" Or func.IdentLower() = "compare" Or func.IdentLower() = "sendmessage" Or func.IdentLower() = "new" Or func.IdentLower() = "delete" Then
+			If classDecl.munged = "bbObjectClass" Then
+				For Local decl:TFuncDecl = EachIn classDecl.Decls()
+					If Not decl.IsSemanted() Then
+						decl.Semant
+					End If
+					If decl.IdentLower() = func.IdentLower() Then
+						Local res:Int = decl.EqualsFunc(func)
+						If res Then
+							func.equalsBuiltIn = True
+						End If
+						Return res
+					End If
+				Next
+			End If
+			If classDecl.superClass Then
+				Return equalsBuiltInFunc(classDecl.superClass, func, True)
+			End If
+		End If
+		func.equalsBuiltIn = False
+		Return False
+	End Method
+
+	Method equalsIfcBuiltInFunc:Int(classDecl:TClassDecl, func:TFuncDecl, checked:Int = False)
+		If checked Or func.IdentLower() = "new" Or func.IdentLower() = "delete" Then
+			If classDecl.munged = "bbObjectClass" Then
+				For Local decl:TFuncDecl = EachIn classDecl.Decls()
+					If Not decl.IsSemanted() Then
+						decl.Semant
+					End If
+					If decl.IdentLower() = func.IdentLower() Then
+						Return decl.EqualsFunc(func)
+					End If
+				Next
+			End If
+			If classDecl.superClass Then
+				Return equalsIfcBuiltInFunc(classDecl.superClass, func, True)
+			End If
+		End If
+		Return False
+	End Method
+
+	Method MungFuncDecl( fdecl:TFuncDecl )
+
+		If fdecl.munged Return
+		
+		Local funcs:TFuncDeclList=TFuncDeclList(funcMungs.ValueForKey( fdecl.ident ))
+		If funcs
+			For Local tdecl:TFuncDecl=EachIn funcs
+				If fdecl.EqualsArgs( tdecl ) And fdecl.scope = tdecl.scope
+					fdecl.munged=tdecl.munged
+					Return
+				EndIf
+			Next
+		Else
+			funcs=New TFuncDeclList
+			funcMungs.Insert fdecl.ident,funcs
+		EndIf
+
+		If fdecl.scope Then
+			Local id:String = fdecl.ident
+
+			If fdecl.attrs & FUNC_OPERATOR Then
+				id = MungSymbol(id)
+			End If
+			
+			fdecl.munged = fdecl.ParentScope().munged + "_" + id
+			
+			If Not equalsBuiltInFunc(fdecl.classScope(), fdecl) And Not fdecl.noMangle Then
+				fdecl.munged :+ MangleMethod(fdecl)
+			End If
+			
+			' fields are lowercase with underscore prefix.
+			' a function pointer with FUNC_METHOD is a field function pointer.
+			'If TFieldDecl(fdecl) Or (TFuncDecl(decl) And (decl.attrs & FUNC_METHOD) And (decl.attrs & FUNC_PTR)) Then
+			'	munged = "_" + munged.ToLower()
+			'End If
+		Else
+			fdecl.munged="bb_"+fdecl.ident
+		End If
+		
+		funcs.AddLast fdecl
+	End Method
+	
+	Method MungSymbol:String(sym:String)
+		Select sym
+			Case "*"
+				Return "_mul"
+			Case "/"
+				Return "_div"
+			Case "+"
+				Return "_add"
+			Case "-"
+				Return "_sub"
+			Case "&"
+				Return "_and"
+			Case "|"
+				Return "_or"
+			Case "~~"
+				Return "_xor"
 			Case "^"
 				Return "_pow"
-			Case ":*"
-				Return "_muleq"
-			Case ":/"
-				Return "_diveq"
-			Case ":+"
-				Return "_addeq"
-			Case ":-"
-				Return "_subeq"
-			Case ":&"
-				Return "_andeq"
-			Case ":|"
-				Return "_oreq"
-			Case ":~~"
-				Return "_xoreq"
+			Case ":*"
+				Return "_muleq"
+			Case ":/"
+				Return "_diveq"
+			Case ":+"
+				Return "_addeq"
+			Case ":-"
+				Return "_subeq"
+			Case ":&"
+				Return "_andeq"
+			Case ":|"
+				Return "_oreq"
+			Case ":~~"
+				Return "_xoreq"
 			Case ":^"
 				Return "_poweq"
-			Case "<"
-				Return "_lt"
-			Case "<="
-				Return "_le"
-			Case ">"
-				Return "_gt"
-			Case ">="
-				Return "_ge"
-			Case "="
-				Return "_eq"
-			Case "<>"
-				Return "_ne"
-			Case "mod"
-				Return "_mod"
-			Case "shl"
-				Return "_shl"
-			Case "shr"
-				Return "_shr"
-		End Select
-		Return "?? unknown symbol ?? : " + sym
-	End Method
-	
-	Method MungDecl( decl:TDecl, addIfNotInScope:Int = False )
-
-		If decl.munged Then
-			' ensure function args get into local scope correctly.
-			If addIfNotInScope Then
-				If Not mungScope.Contains( decl.munged ) Then
-					mungScope.Insert(decl.munged, decl)
-				End If
-			End If
-			Return
-		End If
-
-		Local fdecl:TFuncDecl=TFuncDecl( decl )
-		
-		' apply mangling to methods and New (ctors)
-		' but don't apply mangling to function pointers
-		If fdecl And fdecl.ClassScope() And Not (fdecl.attrs & FUNC_PTR)
-			MungFuncDecl( fdecl )
-			Return
-		End If
-		
-		Local id$=decl.ident,munged$
-		
-		'this lot just makes output a bit more readable...
-'		Select ENV_LANG
-'		Case "js"
-'			If TModuleDecl( decl.scope ) Or TGlobalDecl( decl ) Or (fdecl And Not fdecl.IsMethod())
-'				munged=decl.ModuleScope().munged+"_"+id
-'			EndIf
-'		Case "as"
-'			If TModuleDecl( decl.scope )
-'				munged=decl.ModuleScope().munged+"_"+id
-'			EndIf
-'		Case "cs"
-'			If TClassDecl( decl )
-'				munged=decl.ModuleScope().munged+"_"+id
-'			EndIf
-'		Case "java"
-'			If TClassDecl( decl )
-'				munged=decl.ModuleScope().munged+"_"+id
-'			EndIf
-'		Case "cpp"
-			If TModuleDecl( decl.scope )
-				munged=decl.ModuleScope().munged+"_"+id
-				
-				If TClassDecl(decl) And TClassDecl(decl).instArgs Then
-					For Local ty:TType = EachIn TClassDecl(decl).instArgs
-						munged :+ TransMangleType(ty)
-					Next
-				End If
-			EndIf
-
-			If TModuleDecl( decl )
-				munged=decl.ModuleScope().munged+"_"+id
-			EndIf
-
-'		End Select
-'DebugStop
-
-		If Not munged
-			If TLocalDecl( decl )
-				munged="bbt_"+id
-			Else
-				If decl.scope Then
-					munged = decl.scope.munged + "_" + id
-					
-					If TClassDecl(decl) And TClassDecl(decl).instArgs Then
-						For Local ty:TType = EachIn TClassDecl(decl).instArgs
-							munged :+ TransMangleType(ty)
-						Next
-					End If
-					
-					' fields are lowercase with underscore prefix.
-					' a function pointer with FUNC_METHOD is a field function pointer.
-					If TFieldDecl(decl) Or (TFuncDecl(decl) And (decl.attrs & FUNC_METHOD) And (decl.attrs & FUNC_PTR)) Then
-						munged = "_" + munged.ToLower()
-					End If
-				Else
-					munged="bb_"+id
-				End If
-			EndIf
-		EndIf
-
-		'sanitize non-mung-able characters
-		munged = TStringHelper.Sanitize(munged)
-
-
-		'add an increasing number to identifier if already used  
-		If mungScope.Contains( munged )
-			Local i:Int=1
-			Repeat
-				i:+1
-			Until Not mungScope.Contains( munged + i )
-			munged :+ i
-		EndIf
-
-		mungScope.Insert(munged, decl)
-		decl.munged=munged
-		
-		' a function pointers' real function is stored in "func" - need to set its munged to match the parent.
-		If TValDecl(decl) Then
-			If TFunctionPtrType(TValDecl(decl).ty) Then
-				TFunctionPtrType(TValDecl(decl).ty).func.munged = munged
-			End If
-		End If
-		
-	End Method
-
-Rem
-	Method MungDecl( decl:TDecl )
-
-		If decl.munged Return
-
-		Local fdecl:TFuncDecl=TFuncDecl( decl )
-		If fdecl And fdecl.IsMethod() Then
-'			DebugStop
-			MungFuncDecl( fdecl )
-			Return
-		End If
-		
-		Local id:String=decl.ident,munged$,scope$
-		
-		If TLocalDecl( decl )
-			scope="$"
-			munged="t_"+id
-		Else If TClassDecl( decl )
-			scope=""
-			munged="c_"+id
-		Else If TModuleDecl( decl )
-			scope=""
-			munged="bb_"+id
-		Else If TClassDecl( decl.scope )
-			scope=decl.scope.munged
-			munged="m_"+id
-		Else If TModuleDecl( decl.scope )
-			'If ENV_LANG="cs" Or ENV_LANG="java"
-			'	scope=decl.scope.munged
-			'	munged="g_"+id
-			'Else
-				scope=""
-				munged=decl.scope.munged+"_"+id
-			'EndIf
-		Else
-			InternalErr
-		EndIf
-		
-		Local set:TMap=TMap(mungedScopes.ValueForKey( scope ))
-		If set
-			If set.Contains( munged.ToLower() )
-				Local id:Int=1
-				Repeat
-					id :+ 1
-					Local t$=munged+id
-					If set.Contains( t.ToLower() ) Continue
-					munged=t
-					Exit
-				Forever
-			End If
-		Else
-			If scope="$"
-				Print "OOPS2"
-				InternalErr
-			EndIf
-			set=New TMap
-			mungedScopes.Insert scope,set
-		End If
-		set.Insert munged.ToLower(), ""
-		decl.munged=munged
-	End Method
-End Rem
-
-
-
-	
-	Method Bra$( str$ )
-		If str.StartsWith( "(" ) And str.EndsWith( ")" )
-			Local n:Int=1
-			For Local i:Int=1 Until str.Length-1
-				Select str[i..i+1]
-				Case "("
-					n:+1
-				Case ")"
-					n:-1
-					If Not n Return "("+str+")"
-				End Select
-			Next
-			If n=1 Return str
-'			If str.FindLast("(")<str.Find(")") Return str
-		EndIf
-		Return "("+str+")"
-	End Method
-	
-	'Utility C/C++ style...
-	Method Enquote$( str$ )
-		Return LangEnquote( str )
-	End Method
-	
-	Method EscapeChars:String(str:String)
-		If str Then
-			Local found:Int = False
-			For Local i:Int = 0 Until str.length
-				If str[i] > 127 Then
-					found = True
-					Exit
-				End If
-			Next
-			
-			If Not found Then
-				Return str
-			End If
-		
-			Local s:String
-			
-			For Local i:Int = 0 Until str.length
-				Local char:Int = str[i]
-				
-				If char < 128 Then
-					s :+ Chr(char)
-				Else
-					s :+ "~~" + char + "~~"
-				End If
-			Next
-			
-			Return s
-		End If
-	End Method
-
-	Method TransUnaryOp$( op$ )
-		Select op
-		Case "+" Return "+"
-		Case "-" Return "-"
-		Case "~~" Return op
-		Case "not" Return "!"
-		End Select
-		InternalErr
-	End Method
-	
-	Method TransBinaryOp$( op$,rhs$ )
-'DebugLog "TransBinaryOp '" + op + "' : '" + rhs + "'"
-op = mapSymbol(op)
-		Select op
-		Case "+","-"
-			If rhs.StartsWith( op ) Return op+" "
-			Return op
-		Case "*","/" Return op
-		Case "shl" Return "<<"
-		Case "shr" Return ">>"
-		Case "sar" Return ">>"
-		Case "mod" Return " % "
-		Case "and" Return " && "
-		Case "or" Return " || "
-		Case "=" Return "=="
-		Case "<>" Return "!="
-		Case "<","<=",">",">=" Return op
-		Case "=<" Return "<="
-		Case "=>" Return ">="
-		Case "&","|" Return op
-		Case "~~" Return "^"
-		Case "<<", ">>" Return Op
-		Case "%" Return Op
-		End Select
-		InternalErr
-	End Method
-	
-	Method TransAssignOp$( op$ )
-op = mapSymbol(op)
-		Select op
-		Case ":mod" Return "%="
-		Case ":shl" Return "<<="
-		Case ":shr" Return ">>="
-		Case ":sar" Return ">>="
-		End Select
-		Return op
-	End Method
-	
-	Method ExprPri:Int( expr:TExpr )
-		'
-		'1=primary,
-		'2=postfix
-		'3=prefix
-		'
-		If TNewObjectExpr( expr )
-			Return 3
-		Else If TUnaryExpr( expr )
-			Select TUnaryExpr( expr ).op
-			Case "+","-","~~","not" Return 3
-			End Select
-			InternalErr
-		Else If TBinaryExpr( expr )
-			Select TBinaryExpr( expr ).op
-			Case "^" Return 4
-			Case "*","/","mod","%" Return 5
-			Case "+","-" Return 6
-			Case "shl","shr", "sar","<<", ">>" Return 7
-			Case "<","<=",">",">=", "=<", "=>" Return 8
-			Case "=","<>" Return 9
-			Case "&" Return 10
-			Case "~~" Return 11
-			Case "|" Return 12
-			Case "and" Return 13
-			Case "or" Return 14
-			End Select
-			InternalErr
-		EndIf
-		Return 2
-	End Method
-	
-	Method TransSubExpr$( expr:TExpr,pri:Int=2 )
-		Local t_expr$=expr.Trans()
-		'If expr.exprType._flags & TTYPE.T_VAR Then
-		'	t_expr = Bra("*" + t_expr)
-		'End If
-		If ExprPri( expr )>pri t_expr=Bra( t_expr )
-		Return t_expr
-	End Method
-	
-	Method TransExprNS$( expr:TExpr )
-		If TVarExpr( expr ) Return expr.Trans()
-		If TConstExpr( expr ) Return expr.Trans()
-		Return CreateLocal( expr )
-	End Method
-	
-	Method CreateLocal$( expr:TExpr, init:Int = True, vol:Int = True )
-		Local tmp:TLocalDecl=New TLocalDecl.Create( "",expr.exprType,expr, True, , vol )
-		MungDecl tmp
-		Emit TransLocalDecl( tmp,expr, True, init )+";"
-
-		EmitGDBDebug(_errInfo)
-		
-		Return tmp.munged
-	End Method
-
-	'***** Utility *****
-
-	Method TransLocalDecl$( decl:TLocalDecl,init:TExpr, declare:Int = False, outputInit:Int = True ) Abstract
-
-	Method TransGlobalDecl$( gdecl:TGlobalDecl ) Abstract
-	
-	Method EmitPushErr()
-	End Method
-	
-	Method EmitSetErr( errInfo$ )
-	End Method
-	
-	Method EmitPopErr()
-	End Method
-	
-	'***** Declarations *****
-	
-	Method TransGlobal$( decl:TGlobalDecl ) Abstract
-	
-	Method TransField$( decl:TFieldDecl,lhs:TExpr ) Abstract
-	
-	Method TransFunc$( decl:TFuncDecl,args:TExpr[],lhs:TExpr, sup:Int = False, scope:TScopeDecl = Null ) Abstract
-	
-	Method TransSuperFunc$( decl:TFuncDecl,args:TExpr[], scope:TScopeDecl ) Abstract
-	
-	
-	'***** Expressions *****
-	
-	Method TransConstExpr$( expr:TConstExpr ) Abstract
-	
-	Method TransNewObjectExpr$( expr:TNewObjectExpr ) Abstract
-	
-	Method TransNewArrayExpr$( expr:TNewArrayExpr ) Abstract
-	
-	Method TransSelfExpr$( expr:TSelfExpr ) Abstract
-	
-	Method TransCastExpr$( expr:TCastExpr ) Abstract
-	
-	Method TransUnaryExpr$( expr:TUnaryExpr ) Abstract
-	
-	Method TransBinaryExpr$( expr:TBinaryExpr ) Abstract
-	
-	Method TransIndexExpr$( expr:TIndexExpr ) Abstract
-	
-	Method TransSliceExpr$( expr:TSliceExpr ) Abstract
-	
-	Method TransArrayExpr$( expr:TArrayExpr ) Abstract
-	
-	Method TransArraySizeExpr$ ( expr:TArraySizeExpr ) Abstract
-	
-	Method TransIntrinsicExpr$( decl:TDecl,expr:TExpr,args:TExpr[]=Null ) Abstract
-	
-	Method TransArgs$( args:TExpr[],decl:TFuncDecl, objParam:String = Null ) Abstract
-
-	Method EmitDebugEnterScope(block:TBlockDecl) Abstract
-	
-	Method EmitLocalDeclarations(decl:TScopeDecl, v:TValDecl = Null) Abstract
-	
-	Method TransType$( ty:TType, ident:String, fpReturnTypeFunctionArgs:String = Null, fpReturnTypeClassFunc:Int = False) Abstract
-
-	Method TransObject:String(decl:TScopeDecl, this:Int = False) Abstract
-	
-	Method BeginLocalScope()
-		mungStack.Push mungScope
-		mungScope:TMap=New TMap'<TDecl>
-'		mungedScopes.Insert "$",New TMap
-		
-		If opt_debug Then
-			localScopeStack.Push localScope
-			localScope = New TStack
-		End If
-	End Method
-	
-	Method EndLocalScope()
-		mungScope=TMap(mungStack.Pop())
-'		mungedScopes.Insert "$",Null
-
-		If opt_debug Then
-			localScope = TStack(localScopeStack.Pop())
-		End If
-	End Method
-
-Rem	
-	Method MungMethodDecl( fdecl:TFuncDecl )
-
-		If fdecl.munged Return
-		
-		If fdecl.overrides
-			MungMethodDecl fdecl.overrides
-			fdecl.munged=fdecl.overrides.munged
-			Return
-		EndIf
-		
-		Local funcs:=funcMungs.Get( fdecl.ident )
-		If funcs
-			For Local tdecl:=EachIn funcs
-				If fdecl.EqualsArgs( tdecl )
-					fdecl.munged=tdecl.munged
-					Return
-				EndIf
-			Next
-		Else
-			funcs=New FuncDeclList
-			funcMungs.Set fdecl.ident,funcs
-		EndIf
-		
-		Local id:=fdecl.ident
-		If mungedFuncs.Contains( id )
-			Local n:=1
-			Repeat
-				n+=1
-				id=fdecl.ident+String(n)
-			Until Not mungedFuncs.Contains( id )
-		EndIf
-		
-		mungedFuncs.Set id,fdecl
-		fdecl.munged="p_"+id
-		funcs.AddLast fdecl
-	End
-End Rem	
-	'***** Simple statements *****
-	
-	'Expressions
-	Method TransStmtExpr$( expr:TStmtExpr )
-		Local t$=expr.stmt.Trans()
-		If t Emit t+";"
-		Return expr.expr.Trans()
-	End Method
-	
-	Method TransTemplateCast$( ty:TType,src:TType,expr$ )
-		Return expr
-	End Method
-	
-	Method TransVarExpr$( expr:TVarExpr )
-		Local decl:TVarDecl=TVarDecl( expr.decl.actual )
-
-		If decl.munged.StartsWith( "$" ) Return TransIntrinsicExpr( decl,Null )
-		
-		If TLocalDecl( decl ) Then
-			If decl.ty._flags & TType.T_VAR Then
-				Return "*" + decl.munged
-			Else
-				Return decl.munged
-			End If
-		End If
-		
-		If TFieldDecl( decl ) Return TransField( TFieldDecl( decl ),Null )
-		
-		If TGlobalDecl( decl ) Return TransGlobal( TGlobalDecl( decl ) )
-		
-		InternalErr
-	End Method
-	
-	Method TransMemberVarExpr$( expr:TMemberVarExpr )
-		Local decl:TVarDecl=TVarDecl( expr.decl.actual )
-		
-		If decl.munged.StartsWith( "$" ) Return TransIntrinsicExpr( decl,expr.expr )
-		
-		If TFieldDecl( decl ) Return TransField( TFieldDecl( decl ),expr.expr )
-
-		If TGlobalDecl( decl ) Return TransGlobal( TGlobalDecl( decl ) )
-
-		InternalErr
-	End Method
-	
-	Method TransInvokeExpr$( expr:TInvokeExpr )
-		Local decl:TFuncDecl=TFuncDecl( expr.decl.actual ),t$
-
-		If Not decl.munged Then
-			MungDecl decl
-		End If
-		
-		'If (decl.attrs & FUNC_PTR) And (decl.attrs & FUNC_INIT) And Not expr.InvokedWithBraces Return decl.munged
-		
-		'If ((decl.attrs & FUNC_PTR) Or (expr.decl.attrs & FUNC_PTR)) And Not expr.InvokedWithBraces Return decl.munged
-		
-		'If Not expr.InvokedWithBraces And expr.IsRhs Return decl.munged
-		
-		' if the call was a statement (even one written without parentheses), then invokedWithBraces is true
-		' so no complicated checks are needed here; if invokedWithBraces is false, this is definitely not a call
-		If Not expr.InvokedWithBraces Then Return decl.munged
-		
-		If decl.munged.StartsWith( "$" ) Return TransIntrinsicExpr( decl,Null,expr.args )
-		
-		If processingReturnStatement = 1 Then
-			If decl Then
-				processingReturnStatement :+ 1
-				Return CreateLocal(expr)
-			End If
-		Else
-			Return TransFunc( TFuncDecl(decl),expr.args,Null )
-		End If
-		
-		InternalErr
-	End Method
-	
-	Method TransInvokeMemberExpr$( expr:TInvokeMemberExpr )
-		Local decl:TFuncDecl=TFuncDecl( expr.decl.actual ),t$
-
-		If decl.munged.StartsWith( "$" ) Return TransIntrinsicExpr( decl,expr.expr,expr.args )
-		
-		If processingReturnStatement = 1 Then
-			If decl Then
-				processingReturnStatement :+ 1
-				Return CreateLocal(expr)
-			End If
-		Else
-			Return TransFunc( TFuncDecl(decl),expr.args,expr.expr )	
-		End If
-		
-		InternalErr
-	End Method
-	
-	Method TransInvokeSuperExpr$( expr:TInvokeSuperExpr )
-		Local decl:TFuncDecl=TFuncDecl( expr.origFuncDecl.actual ),t$
-
-		If decl.munged.StartsWith( "$" ) Return TransIntrinsicExpr( decl,expr )
-		
-		If processingReturnStatement = 1 Then
-			If decl Then
-				processingReturnStatement :+ 1
-				Return CreateLocal(expr)
-			End If
-		Else
-			If decl Return TransSuperFunc( TFuncDecl( expr.funcDecl ),expr.args, expr.classScope )
-		End If
-		
-		InternalErr
-	End Method
-	
-	Method TransFuncCallExpr:String( expr:TFuncCallExpr )
-
-		If TIndexExpr(expr.expr) And TArrayType(TIndexExpr(expr.expr).expr.exprType) And TFunctionPtrType(TArrayType(TIndexExpr(expr.expr).expr.exprType).elemType) Then
-			Local decl:TDecl = TFunctionPtrType(TArrayType(TIndexExpr(expr.expr).expr.exprType).elemType).func.actual
-			decl.Semant()
-			expr.args=expr.CastArgs( expr.args,TFuncDecl(decl) )
-			Return expr.expr.Trans() + TransArgs(expr.args, TFuncDecl(decl))
-		End If
-
-		' hmmm, complicated - a function returning and invoking a function pointer...		
-		If TInvokeExpr(expr.expr) And TFunctionPtrType(TInvokeExpr(expr.expr).exprType) Then
-			Local decl:TDecl = TFunctionPtrType(TInvokeExpr(expr.expr).exprType).func.actual
-			decl.Semant()
-			expr.args=expr.CastArgs( expr.args,TFuncDecl(decl) )
-			Return expr.expr.Trans() + TransArgs(expr.args, TFuncDecl(decl))
-		End If
-		
-		InternalErr
-	End Method
-	
-	Method TransExprStmt$( stmt:TExprStmt )
-		Return stmt.expr.TransStmt()
-	End Method
-	
-	Method TransAssignStmt$( stmt:TAssignStmt )
-		If stmt.rhs Return stmt.lhs.TransVar()+TransAssignOp(stmt.op)+stmt.rhs.Trans()
-		Return stmt.lhs.Trans()
-	End Method
-	
-	Method TransReturnStmt$( stmt:TReturnStmt )
-
-		Local t$="return"
-		unreachable=True
-		If stmt.expr Then
-
-			If TObjectType(stmt.expr.exprType) And TNullDecl(TObjectType(stmt.expr.exprType).classDecl) Then
-				If IsPointerType(stmt.fRetType, 0, TType.T_POINTER) Or IsNumericType(stmt.fRetType) Then
-					t:+ " 0"
-				End If
-				If TStringType(stmt.fRetType) Then
-					t:+ " &bbEmptyString"
-				End If
-				If TArrayType(stmt.fRetType) Then
-					t:+ " &bbEmptyArray"
-				End If
-
-			Else
-				
-				If TObjectType(stmt.expr.exprType) And TObjectType(stmt.expr.exprType).classDecl.IsStruct() And TConstExpr(stmt.expr) And Not TConstExpr(stmt.expr).value Then
-					Local lvar:String = CreateLocal(stmt.expr)
-					t :+ " " + lvar
-				Else
-
-					Local s:String
-					
-					' cast to function return type
-					If TObjectType(stmt.fRetType) Then
-						s :+ Bra(transObject(TObjectType(stmt.fRetType).classDecl))
-					End If
-
-					s :+ stmt.expr.Trans()
-					
-					' we have some temp variables that need to be freed before we can return
-					' put the results into a new variable, and return that.
-					If customVarStack.Count() > 0 Then
-						If Not TFunctionPtrType( stmt.expr.exprType ) Then
-							Emit TransType(stmt.expr.exprType, "rt_") + " rt_ = " + s + ";"
-						Else
-							Emit TransType(stmt.expr.exprType, "rt_") + " = " + s + ";"
-						End If
-						t:+ " rt_"
-					Else
-						t:+" " + s
-					End If
-				End If
-			End If
-			
-		End If
-
-		FreeVarsIfRequired()
-		
-		' if this is a Delete() method, we need to call the dtor first
-		Local funcScope:TFuncDecl = _env.FuncScope()
-		If funcScope And funcScope.IdentLower() = "delete" Then
-			Local classScope:TClassDecl = funcScope.ClassScope()
-			If classScope Then
-				EmitClassDeclDeleteDtor(classScope)
-			End If
-		End If
-		
-		Return t
-	End Method
-	
-	Method NextExitId:Int(bc:TTryBreakCheck)
-		If Not bc.exitId Then
-			exitLabelId :+ 1
-			bc.exitId = exitLabelId
-		End If
-		
-		Return bc.exitId
-	End Method
-
-	Method NextContId:Int(bc:TTryBreakCheck)
-		If Not bc.contId Then
-			contLabelId :+ 1
-			bc.contId = contLabelId
-		End If
-		
-		Return bc.contId
-	End Method
-
-	Method TransContinueStmt$( stmt:TContinueStmt )
-		unreachable=True
-
-		Local contLoop:TStmt
-		' if we are continuing with a loop label, we'll need to find it in the stack
-		If stmt.label And TLoopLabelExpr(stmt.label) Then
-			contLoop = TLoopLabelExpr(stmt.label).loop
-		End If
-		' get count of Try statements in the stack in this loop
-		Local count:Int = LoopTryDepth(contLoop)
-		If count > 0 Then
-			Local bc:TTryBreakCheck = GetTopLoop(contLoop)
-			If bc Then
-				NextContId(bc)
-				For Local i:Int = 0 Until count
-					Emit "bbExLeave();"
-					If opt_debug Then
-						Emit "bbOnDebugPopExState();"
-					End If
-				Next
-				Emit "goto " + TransLabelCont(bc, False)
-			Else
-				InternalErr
-			End If
-		Else
-		 	' For debug builds, we need to rollback the local scope stack correctly
-			count = 0
-			
-			If opt_debug And TLoopStmt(contLoop) And Not TLoopStmt(contLoop).block.IsNoDebug() Then
-				count = LoopLocalScopeDepth(contLoop)
-			End If
-			
-			If count > 0 Then
-				Local bc:TTryBreakCheck = GetTopLocalLoop(contLoop)
-				If bc Then
-					NextContId(bc)
-					For Local i:Int = 0 Until count
-						Emit "bbOnDebugLeaveScope();"
-					Next
-					Emit "goto " + TransLabelCont(bc, False)
-				Else
-					InternalErr
-				End If
-			Else
-
-				If opt_debug And stmt.loop And Not stmt.loop.block.IsNoDebug() Then
-					count = LoopLocalScopeDepth(Null)
-				End If
-				For Local i:Int = 0 Until count
-					Emit "bbOnDebugLeaveScope();"
-				Next
-
-				' No Try statements in the stack here..
-				If stmt.label And TLoopLabelExpr(stmt.label) Then
-					Emit "goto " + TransLoopLabelCont(TLoopLabelExpr(stmt.label).loop.loopLabel.realIdent, False)
-				Else
-					Return "continue"
-				End If
-			End If
-		End If
-	End Method
-	
-	Method TransBreakStmt$( stmt:TBreakStmt )
-		unreachable=True
-		broken:+1
-
-		Local brkLoop:TStmt
-		' if we are exiting with a loop label, we'll need to find it in the stack
-		If stmt.label And TLoopLabelExpr(stmt.label) Then
-			brkLoop = TLoopLabelExpr(stmt.label).loop
-		End If
-		' get count of Try statements in the stack in this loop
-		Local count:Int = LoopTryDepth(brkLoop)
-		If count > 0 Then
-			Local bc:TTryBreakCheck = GetTopLoop(brkLoop)
-			If bc Then
-				NextExitId(bc)
-				For Local i:Int = 0 Until count
-					Emit "bbExLeave();"
-					If opt_debug Then
-						Emit "bbOnDebugPopExState();"
-					End If
-				Next
-				Emit "goto " + TransLabelExit(bc, False)
-			Else
-				InternalErr
-			End If
-		Else
-		 	' For debug builds, we need to rollback the local scope stack correctly
-			count = 0
-			
-			If opt_debug And TLoopStmt(brkLoop) And Not TLoopStmt(brkLoop).block.IsNoDebug() Then
-				count = LoopLocalScopeDepth(brkLoop)
-			End If
-			
-			If count > 0 Then
-				Local bc:TTryBreakCheck = GetTopLocalLoop(brkLoop)
-				If bc Then
-					NextExitId(bc)
-					For Local i:Int = 0 Until count
-						Emit "bbOnDebugLeaveScope();"
-					Next
-					Emit "goto " + TransLabelExit(bc, False)
-				Else
-					InternalErr
-				End If
-			Else
-
-				If opt_debug And stmt.loop And Not stmt.loop.block.IsNoDebug() Then
-					count = LoopLocalScopeDepth(Null)
-				End If
-				For Local i:Int = 0 Until count
-					Emit "bbOnDebugLeaveScope();"
-				Next
-				
-				' No Try statements in the stack here..
-				If stmt.label And TLoopLabelExpr(stmt.label) Then
-					Emit "goto " + TransLoopLabelExit(TLoopLabelExpr(stmt.label).loop.loopLabel.realIdent, False)
-				Else
-					Return "break"
-				End If
-			End If
-		End If
-	End Method
-	
-	Method TransTryStmt$( stmt:TTryStmt )
-	End Method
-	
-	Method EmitTryStack() Abstract
-
-	Method TransThrowStmt$( stmt:TThrowStmt )
-	End Method
-	
-
-	Method TransBuiltinExpr$( expr:TBuiltinExpr )
-		If TMinExpr(expr) Return TransMinExpr(TMinExpr(expr))
-		If TMaxExpr(expr) Return TransMaxExpr(TMaxExpr(expr))
-		If TAbsExpr(expr) Return TransAbsExpr(TAbsExpr(expr))
-		If TAscExpr(expr) Return TransAscExpr(TAscExpr(expr))
-		If TChrExpr(expr) Return TransChrExpr(TChrExpr(expr))
-		If TSgnExpr(expr) Return TransSgnExpr(TSgnExpr(expr))
-		If TLenExpr(expr) Return TransLenExpr(TLenExpr(expr))
-		If TSizeOfExpr(expr) Return TransSizeOfExpr(TSizeOfExpr(expr))
-		Err "TODO : TransBuiltinExpr()"
-	End Method
-	
-	Method TransMinExpr:String(expr:TMinExpr)
-	End Method
-
-	Method TransMaxExpr:String(expr:TMaxExpr)
-	End Method
-
-	Method TransAbsExpr:String(expr:TAbsExpr)
-	End Method
-
-	Method TransAscExpr:String(expr:TAscExpr)
-	End Method
-
-	Method TransChrExpr:String(expr:TChrExpr)
-	End Method
-
-	Method TransSgnExpr:String(expr:TSgnExpr)
-	End Method
-
-	Method TransLenExpr:String(expr:TLenExpr)
-	End Method
-
-	Method TransSizeOfExpr:String(expr:TSizeOfExpr)
-	End Method
-	
-	Method TransIdentTypeExpr:String(expr:TIdentTypeExpr) Abstract
-	
-	Method TransLabelCont:String(bc:TTryBreakCheck, jmp:Int = True)
-		If jmp Then
-			Return "_contjmp" + bc.contId + ": ;"
-		Else
-			Return "_contjmp" + bc.contId + ";"
-		End If
-	End Method
-	
-	Method TransLabelExit:String(bc:TTryBreakCheck, jmp:Int = True)
-		If jmp Then
-			Return "_exitjmp" + bc.exitId + ": ;"
-		Else
-			Return "_exitjmp" + bc.exitId + ";"
-		End If
-	End Method
-
-	Method TransLoopLabelCont:String(id:String, jmp:Int = True)
-		If jmp Then
-			Return "_loopcont_" + id.ToLower() + ": ;"
-		Else
-			Return "_loopcont_" + id.ToLower() + ";"
-		End If
-	End Method
-
-	Method TransLoopLabelExit:String(id:String, jmp:Int = True)
-		If jmp Then
-			Return "_loopexit_" + id.ToLower() + ": ;"
-		Else
-			Return "_loopexit_" + id.ToLower() + ";"
-		End If
-	End Method
-
-	'***** Block statements - all very C like! *****
-	
-	Method Emit( t$, useIndent:Int = True )
-		If Not t Return
-		If useIndent
-			If t.StartsWith( "}" )
-				indent=indent[..indent.Length-1]
-			EndIf
-		End If
-		LINES.AddLast indent+t
-		'code+=indent+t+"~n"
-		If useIndent
-			If t.EndsWith( "{" )
-				indent:+"~t"
-			EndIf
-		End If
-	End Method
-	
-	Method JoinLines$( file:String )
-		Local _lines:TStringList = TStringList(outputFiles.ValueForKey(file))
-		
-		Local code$=_lines.Join( "~n" )
-		_lines.Clear
-		Return code
-	End Method
-	
-	'returns unreachable status!
-	Method EmitBlock:Int( block:TBlockDecl )
-		Local stmtCount:Int
-'DebugStop
-		'If ENV_CONFIG="debug"
-		'	If TFuncDecl( block ) EmitPushErr
-		'EndIf
-
-
-		PushEnv block
-		
-		' enter scope
-		If opt_debug And Not block.IsNoDebug() And Not block.generated Then
-			PushLoopLocalStack(block)
-			EmitDebugEnterScope(block)
-		End If
-
-		For Local stmt:TStmt=EachIn block.stmts
-		
-			_errInfo=stmt.errInfo
-			
-			If unreachable
-				' Statements following cannot be reached - maybe we have Returned, etc
-				' So don't process any more for this block - they won't be generated now!
-				Exit
-			EndIf
-
-Rem
-			If ENV_CONFIG="debug"
-				Local rs:TReturnStmt=TReturnStmt( stmt )
-				If rs
-					If rs.expr
-						EmitSetErr stmt.errInfo
-						Local t_expr$=TransExprNS( rs.expr )
-						EmitPopErr
-						Emit "return "+t_expr+";"
-					Else
-						EmitPopErr
-						Emit "return;"
-					EndIf
-					unreachable=True
-					Continue
-				EndIf
-				EmitSetErr stmt.errInfo
-			EndIf
-End Rem
-			If opt_debug And Not block.IsNoDebug() Then
-				' only for user-made code
-				If Not stmt.generated Then
-					EmitDebugStmtErrInfo(stmt.errInfo, stmtCount)
-					stmtCount :+ 1
-				End If
-			
-			End If
-
-			EmitGDBDebug(stmt)
-			
-			If TReturnStmt(stmt) And Not tryStack.IsEmpty() Then
-				processingReturnStatement = True
-			End If
-			
-			Local t$=stmt.Trans()
-			
-			processingReturnStatement = False
-			
-			If opt_debug And Not block.IsNoDebug() Then
-				If TReturnStmt(stmt) Then
-					For Local b:TBlockDecl = EachIn localScope
-						Emit "bbOnDebugLeaveScope();"
-					Next
-				End If
-			End If
-
-			If TReturnStmt(stmt) Then
-				EmitTryStack()
-			End If
-			
-			If t Emit t+";"
-
-			If DEBUG And debugOut Then
-				Emit debugOut
-				debugOut = Null
-			End If
-			
-			Local v:String = String(customVarStack.Pop())
-			While v
-				Emit "bbMemFree" + Bra(v) + ";"
-				v = String(customVarStack.Pop())
-			Wend
-			
-		Next
-
-		If opt_debug And Not block.IsNoDebug() And Not block.generated Then
-			PopLoopLocalStack()
-			If Not unreachable Then
-				Emit "bbOnDebugLeaveScope();"
-			End If
-		End If
-
-		Local r:Int=unreachable
-		unreachable=False
-		PopEnv
-		Return r
-	End Method
-	
-	Method TransDeclStmt$( stmt:TDeclStmt, declare:Int = False )
-		Local decl:TLocalDecl=TLocalDecl( stmt.decl )
-		If decl
-			MungDecl decl
-			' only generate local declarations once.
-			If decl.generated Then
-				If Not decl.done Then
-					decl.done = True
-				Else
-					Return ""
-				End If
-			End If
-			Return TransLocalDecl( decl,decl.init, decl.generated Or declare )
-		EndIf
-		Local cdecl:TConstDecl=TConstDecl( stmt.decl )
-		If cdecl
-			Return Null
-		EndIf
-		Local gdecl:TGlobalDecl=TGlobalDecl( stmt.decl )
-		If gdecl Then
-			MungDecl gdecl
-			If gdecl.inited Return Null
-			Return TransGlobalDecl( gdecl )
-		End If
-		InternalErr
-	End Method
-	
-	Method TransIfStmt$( stmt:TIfStmt )
-		If TConstExpr( stmt.expr )
-			If TConstExpr( stmt.expr ).value
-				Emit "{"
-				EmitLocalDeclarations(stmt.thenBlock)
-				If EmitBlock( stmt.thenBlock ) unreachable=True
-				Emit "}"
-			Else If stmt.elseBlock.stmts.First()
-				Emit "{"
-				EmitLocalDeclarations(stmt.elseBlock)
-				If EmitBlock( stmt.elseBlock ) unreachable=True
-				Emit "}"
-			EndIf
-		Else If stmt.elseBlock.stmts.First()
-			Emit "if"+Bra( stmt.expr.Trans() )+"{"
-			EmitLocalDeclarations(stmt.thenBlock)
-			FreeVarsIfRequired(False)
-			PushVarScope
-			Local unr:Int=EmitBlock( stmt.thenBlock )
-			PopVarScope
-			Emit "}else{"
-			EmitLocalDeclarations(stmt.elseBlock)
-			FreeVarsIfRequired
-			Local unr2:Int=EmitBlock( stmt.elseBlock )
-			Emit "}"
-			If unr And unr2 unreachable=True
-		Else
-
-'			Emit "if"+ Bra(TransCondition(stmt.expr)) + "{"
-'			If TVarExpr(stmt.expr) Then
-'				If TObjectType(TVarExpr(stmt.expr).exprType) Then
-'					Emit "if"+Bra( stmt.expr.Trans() + "!= &bbNullObject") + "{"
-'				Else If TStringType(TVarExpr(stmt.expr).exprType)  Then
-'					Emit "if"+Bra( stmt.expr.Trans() + "!= &bbEmptyString") + "{"
-'				Else
-'					Emit "if"+Bra( stmt.expr.Trans() )+"{"
-'				End If
-'			Else
-				Emit "if"+Bra( stmt.expr.Trans() )+"{"
-				FreeVarsIfRequired(False)
-'			End If
-			EmitLocalDeclarations(stmt.thenBlock)
-			PushVarScope
-			Local unr:Int=EmitBlock( stmt.thenBlock )
-			PopVarScope
-			Emit "}"
-			FreeVarsIfRequired
-		EndIf
-	End Method
-	
-	Method FreeVarsIfRequired(removeFromStack:Int = True)
-		If removeFromStack
-			Local v:String = String(customVarStack.Pop())
-			While v
-				Emit "bbMemFree" + Bra(v) + ";"
-				v = String(customVarStack.Pop())
-			Wend
-		Else
-			For Local v:String = EachIn customVarStack
-				Emit "bbMemFree" + Bra(v) + ";"
-			Next
-		End If
-	End Method
-	
-'	Method TransCondition:String(expr:TExpr)
-'		If TVarExpr(expr) Then
-'			If TObjectType(TVarExpr(expr).exprType) Then
-'				Return Bra( expr.Trans() + "!= &bbNullObject")
-'			Else If TStringType(TVarExpr(expr).exprType)  Then
-'				Return Bra( expr.Trans() + "!= &bbEmptyString")
-'			Else
-'				Return Bra( expr.Trans() )
-'			End If
-'		Else
-'			Return Bra( expr.Trans() )
-'		End If
-'	End Method
-	
-	Method TransWhileStmt$( stmt:TWhileStmt )
-		Local nbroken:Int=broken
-
-		Emit "while"+Bra( stmt.expr.Trans() )+"{"
-		
-		Local check:TTryBreakCheck = New TTryBreakCheck
-		check.stmt = stmt
-		PushLoopTryStack(check)
-		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
-			PushLoopLocalStack(check)
-		End If
-		EmitLocalDeclarations(stmt.block)
-		Local unr:Int=EmitBlock( stmt.block )
-		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
-			PopLoopLocalStack
-		End If
-		PopLoopTryStack
-		
-		If check.contId Then
-			Emit TransLabelCont(check)
-		End If
-
-		If stmt.loopLabel Then
-			Emit TransLoopLabelCont(stmt.loopLabel.realIdent, True)
-		End If
-		
-		Emit "}"
-
-		If check.exitId Then
-			Emit TransLabelExit(check)
-		End If
-
-		If stmt.loopLabel Then
-			Emit TransLoopLabelExit(stmt.loopLabel.realIdent, True)
-		End If
-		
-		If broken=nbroken And TConstExpr( stmt.expr ) And TConstExpr( stmt.expr ).value unreachable=True
-		broken=nbroken
-	End Method
-
-	Method TransRepeatStmt$( stmt:TRepeatStmt )
-		Local nbroken:Int=broken
-
-		SetOutputTemp()
-
-		Emit "do{"
-		
-		Local check:TTryBreakCheck = New TTryBreakCheck
-		check.stmt = stmt
-		PushLoopTryStack(check)
-		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
-			PushLoopLocalStack(check)
-		End If
-		EmitLocalDeclarations(stmt.block)
-		Local unr:Int=EmitBlock( stmt.block )
-		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
-			PopLoopLocalStack
-		End If
-		PopLoopTryStack
-
-		If check.contId Then
-			Emit TransLabelCont(check)
-		End If
-
-		If stmt.loopLabel Then
-			Emit TransLoopLabelCont(stmt.loopLabel.realIdent, True)
-		End If
-		
-		SetOutput("source")
-
-		Local s:String = "}while(!"+Bra( stmt.expr.Trans() )+");"
-		
-		SetOutputTemp(True)
-		
-		Emit s
-
-		If check.exitId Then
-			Emit TransLabelExit(check)
-		End If
-
-		If stmt.loopLabel Then
-			Emit TransLoopLabelExit(stmt.loopLabel.realIdent, True)
-		End If
-
-		If broken=nbroken And TConstExpr( stmt.expr ) And Not TConstExpr( stmt.expr ).value unreachable=True
-		broken=nbroken
-	End Method
-
-	Method TransForStmt$( stmt:TForStmt )
-		Local nbroken:Int=broken
-
-		Local init$
-
-		Local decl:Int
-		Local vdecl:TValDecl
-		If TDeclStmt(stmt.init) Then
-			decl = True
-			Emit "{"
-			Emit TransDeclStmt(TDeclStmt(stmt.init), True) + ";"
-			'init = TDeclStmt(stmt.init).decl.munged
-			vdecl = TValDecl(TDeclStmt(stmt.init).decl)
-		Else
-			init=stmt.init.Trans()
-		End If
-		Local expr$=stmt.expr.Trans()
-		Local incr$=stmt.incr.Trans()
-
-		Emit "for("+init+";"+expr+";"+incr+"){"
-
-		Local check:TTryBreakCheck = New TTryBreakCheck
-		check.stmt = stmt
-		PushLoopTryStack(check)
-		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
-			PushLoopLocalStack(check)
-		End If
-		EmitLocalDeclarations(stmt.block, vdecl)
-		Local unr:Int=EmitBlock( stmt.block )
-		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
-			PopLoopLocalStack
-		End If
-		PopLoopTryStack
-		
-		If check.contId Then
-			Emit TransLabelCont(check)
-		End If
-
-		If stmt.loopLabel Then
-			Emit TransLoopLabelCont(stmt.loopLabel.realIdent, True)
-		End If
-		
-		Emit "}"
-		
-		If decl Then
-			Emit "}"
-		End If
-
-		If check.exitId Then
-			Emit TransLabelExit(check)
-		End If
-
-		If stmt.loopLabel Then
-			Emit TransLoopLabelExit(stmt.loopLabel.realIdent, True)
-		End If
-		
-		If broken=nbroken And TConstExpr( stmt.expr ) And TConstExpr( stmt.expr ).value unreachable=True
-		broken=nbroken
-	End Method
-
-	Method TransAssertStmt$( stmt:TAssertStmt ) Abstract
-
-	Method TransEndStmt$( stmt:TEndStmt ) Abstract
-
-	Method TransReleaseStmt$( stmt:TReleaseStmt ) Abstract
-
-	Method TransRestoreDataStmt$( stmt:TRestoreDataStmt ) Abstract
-
-	Method TransReadDataStmt$( stmt:TReadDataStmt ) Abstract
-	
-	Method TransNativeStmt$( stmt:TNativeStmt) Abstract
-
-	'module
-	Method TransApp( app:TAppDecl ) Abstract
-
-Rem	
-	Method MungOverrides( cdecl:TClassDecl )
-		For Local decl:=Eachin cdecl.Semanted
-			Local fdecl:=TFuncDecl( decl )
-			If fdecl And fdecl.overrides
-				If Not fdecl.overrides.munged InternalErr
-				fdecl.munged=fdecl.overrides.munged
-				mungScope.Insert fdecl.munged,fdecl
-			Endif
-		Next
-	End
-End Rem
-	
-	Method PostProcess$( source$ ) 
-		Return source
-	End Method
-	
-	Method SetOutput( file:String )
-		Local _lines:TStringList = TStringList(outputFiles.ValueForKey(file))
-		
-		If Not _lines Then
-			_lines = New TStringList
-			outputFiles.Insert(file, _lines)
-		End If
-		
-		LINES = _lines
-		
-	End Method
-
-	Method SetOutputTemp( fin:Int = False )
-		Global tmpLevel:Int = 0
-	
-		If Not fin Then
-			tmpLevel :+ 1
-
-			Local _lines:TStringList = New TStringList
-			outputFiles.Insert("tmp" + tmpLevel, _lines)
-	
-			LINES = _lines
-		Else
-			Local _lines:TStringList = TStringList(outputFiles.ValueForKey("tmp" + tmpLevel))
-			
-			tmpLevel :- 1
-		
-			If Not tmpLevel Then
-				SetOutput("source")
-			Else
-				LINES = TStringList(outputFiles.ValueForKey("tmp" + tmpLevel))
-			End If
-			
-			If _lines Then
-				For Local line:String = EachIn _lines
-					LINES.AddLast(line)
-				Next
-			End If
-			
-		End If
-	End Method
-
-	Method DebugPrint(text:String, func:String = Null, trans:Int = False)
-		Global count:Int
-		Global lastFunc:String
-		
-		If func Then
-			lastFunc = func
-		End If
-		
-		Local s:String = "fprintf(stderr," + "~q" + lastFunc + " : " + count + " :: " + text + "\n~q)" + ";fflush(stderr);"
-		
-		If trans Then
-			debugOut :+ indent + s + "~n"
-		Else
-			Emit s
-		End If
-		count :+ 1
-	End Method
-	
-	Method DebugString(s:String, func:String = Null, trans:Int = False)
-		' bbNullObject test
-		If trans Then
-			debugOut :+ indent + "if (" + s + "==&bbNullObject) {~n"
-		Else
-			Emit "if (" + s + "==&bbNullObject) {"
-		End If
-		DebugPrint("Invalid Null String : " + s, func, trans)
-		If trans Then
-			debugOut :+ indent + "}~n"
-		Else
-			Emit "}"
-		End If
-	End Method
-
-	Method DebugArray(s:String, func:String = Null, trans:Int = False)
-		' bbNullObject test
-		If trans Then
-			debugOut :+ indent + "if (" + s + "==&bbNullObject) {~n"
-		Else
-			Emit "if (" + s + "==&bbNullObject) {"
-		End If
-		DebugPrint("Invalid Null Array : " + s, func, trans)
-		If trans Then
-			debugOut :+ indent + "}~n"
-		Else
-			Emit "}"
-		End If
-	End Method
-
-	Method DebugObject(ty:TType, id:String, func:String = Null, trans:Int = False)
-		If TObjectType(ty) Or TStringType(ty) Or TArrayType(ty) Then
-			' null test
-			If trans Then
-				debugOut :+ indent + "if (" + id + "==NULL) {~n"
-			Else
-				Emit "if (" + id + "==NULL) {"
-			End If
-			DebugPrint("Null Pointer : " + id, func, trans)
-			If trans Then
-				If ABORT_ON_NULL Then
-					debugOut :+ indent + "abort();~n"
-				End If
-				debugOut :+ indent + "}~n"
-			Else
-				If ABORT_ON_NULL Then
-					Emit "abort();~n"
-				End If
-				Emit "}"
-			End If
-		End If
-		
-		If TStringType(ty) Then
-			DebugString(id, func, trans)
-		Else If TArrayType(ty) Then
-			DebugArray(id, func, trans)
-		End If
-	End Method
-	
-	Method EmitDebugStmtErrInfo(info:String, count:Int)
-		' extract from info
-		info = info[1..info.length-1]
-		Local infoArray:String[] = info.Split(";")
-
-		Local dbg:String = "struct BBDebugStm __stmt_" + count + " = {"
-		dbg :+ Enquote(infoArray[0]) + ", "
-		dbg :+ infoArray[1] + ", "
-		dbg :+ infoArray[2] + "};"
-		Emit dbg
-		Emit "bbOnDebugEnterStm(&__stmt_" + count + ");" 
-	End Method
-	
-	Method EmitGDBDebug(obj:Object)
-		If opt_gdbdebug Then
-			If TStmt(obj) Then
-				Local stmt:TStmt = TStmt(obj)
-				Local infoArray:String[] = stmt.errInfo[1..stmt.errInfo.length-1].Split(";")
-				If Not stmt.generated Then
-					Emit "#line " + infoArray[1] + " " + Enquote(infoArray[0])
-				End If
-			Else If TDecl(obj) Then
-				Local decl:TDecl = TDecl(obj)
-				Local infoArray:String[] = decl.errInfo[1..decl.errInfo.length-1].Split(";")
-				Emit "#line " + infoArray[1] + " " + Enquote(infoArray[0])
-			Else If String(obj) Then
-				Local errInfo:String = String(obj)
-				Local infoArray:String[] = errInfo[1..errInfo.length-1].Split(";")
-				Emit "#line " + infoArray[1] + " " + Enquote(infoArray[0])
-			End If
-		End If
-	End Method
-	
-	Method EmitClassDeclDeleteDtor( classDecl:TClassDecl )
-	End Method
-	
-End Type
-
-Type TTryBreakCheck
-
-	Field contId:Int
-	Field exitId:Int
-
-	Field stmt:TStmt
-	
-End Type
+			Case "<"
+				Return "_lt"
+			Case "<="
+				Return "_le"
+			Case ">"
+				Return "_gt"
+			Case ">="
+				Return "_ge"
+			Case "="
+				Return "_eq"
+			Case "<>"
+				Return "_ne"
+			Case "mod"
+				Return "_mod"
+			Case "shl"
+				Return "_shl"
+			Case "shr"
+				Return "_shr"
+		End Select
+		Return "?? unknown symbol ?? : " + sym
+	End Method
+	
+	Method MungDecl( decl:TDecl, addIfNotInScope:Int = False )
+
+		If decl.munged Then
+			' ensure function args get into local scope correctly.
+			If addIfNotInScope Then
+				If Not mungScope.Contains( decl.munged ) Then
+					mungScope.Insert(decl.munged, decl)
+				End If
+			End If
+			Return
+		End If
+
+		Local fdecl:TFuncDecl=TFuncDecl( decl )
+		
+		' apply mangling to methods and New (ctors)
+		' but don't apply mangling to function pointers
+		If fdecl And fdecl.ClassScope() And Not (fdecl.attrs & FUNC_PTR)
+			MungFuncDecl( fdecl )
+			Return
+		End If
+		
+		Local id$=decl.ident,munged$
+		
+		'this lot just makes output a bit more readable...
+'		Select ENV_LANG
+'		Case "js"
+'			If TModuleDecl( decl.scope ) Or TGlobalDecl( decl ) Or (fdecl And Not fdecl.IsMethod())
+'				munged=decl.ModuleScope().munged+"_"+id
+'			EndIf
+'		Case "as"
+'			If TModuleDecl( decl.scope )
+'				munged=decl.ModuleScope().munged+"_"+id
+'			EndIf
+'		Case "cs"
+'			If TClassDecl( decl )
+'				munged=decl.ModuleScope().munged+"_"+id
+'			EndIf
+'		Case "java"
+'			If TClassDecl( decl )
+'				munged=decl.ModuleScope().munged+"_"+id
+'			EndIf
+'		Case "cpp"
+			If TModuleDecl( decl.scope )
+				munged=decl.ModuleScope().munged+"_"+id
+				
+				If TClassDecl(decl) And TClassDecl(decl).instArgs Then
+					For Local ty:TType = EachIn TClassDecl(decl).instArgs
+						munged :+ TransMangleType(ty)
+					Next
+				End If
+			EndIf
+
+			If TModuleDecl( decl )
+				munged=decl.ModuleScope().munged+"_"+id
+			EndIf
+
+'		End Select
+'DebugStop
+
+		If Not munged
+			If TLocalDecl( decl )
+				munged="bbt_"+id
+			Else If TLoopLabelDecl(decl)
+				munged = "_" + TLoopLabelDecl(decl).realIdent
+			Else
+				If decl.scope Then
+					munged = decl.scope.munged + "_" + id
+					
+					If TClassDecl(decl) And TClassDecl(decl).instArgs Then
+						For Local ty:TType = EachIn TClassDecl(decl).instArgs
+							munged :+ TransMangleType(ty)
+						Next
+					End If
+					
+					' fields are lowercase with underscore prefix.
+					' a function pointer with FUNC_METHOD is a field function pointer.
+					If TFieldDecl(decl) Or (TFuncDecl(decl) And (decl.attrs & FUNC_METHOD) And (decl.attrs & FUNC_PTR)) Then
+						munged = "_" + munged.ToLower()
+					End If
+				Else
+					munged="bb_"+id
+				End If
+			EndIf
+		EndIf
+
+		'sanitize non-mung-able characters
+		munged = TStringHelper.Sanitize(munged)
+
+
+		'add an increasing number to identifier if already used  
+		If mungScope.Contains( munged )
+			Local i:Int=1
+			Repeat
+				i:+1
+			Until Not mungScope.Contains( munged + i )
+			munged :+ i
+		EndIf
+
+		mungScope.Insert(munged, decl)
+		decl.munged=munged
+		
+		' a function pointers' real function is stored in "func" - need to set its munged to match the parent.
+		If TValDecl(decl) Then
+			If TFunctionPtrType(TValDecl(decl).ty) Then
+				TFunctionPtrType(TValDecl(decl).ty).func.munged = munged
+			End If
+		End If
+		
+	End Method
+
+Rem
+	Method MungDecl( decl:TDecl )
+
+		If decl.munged Return
+
+		Local fdecl:TFuncDecl=TFuncDecl( decl )
+		If fdecl And fdecl.IsMethod() Then
+'			DebugStop
+			MungFuncDecl( fdecl )
+			Return
+		End If
+		
+		Local id:String=decl.ident,munged$,scope$
+		
+		If TLocalDecl( decl )
+			scope="$"
+			munged="t_"+id
+		Else If TClassDecl( decl )
+			scope=""
+			munged="c_"+id
+		Else If TModuleDecl( decl )
+			scope=""
+			munged="bb_"+id
+		Else If TClassDecl( decl.scope )
+			scope=decl.scope.munged
+			munged="m_"+id
+		Else If TModuleDecl( decl.scope )
+			'If ENV_LANG="cs" Or ENV_LANG="java"
+			'	scope=decl.scope.munged
+			'	munged="g_"+id
+			'Else
+				scope=""
+				munged=decl.scope.munged+"_"+id
+			'EndIf
+		Else
+			InternalErr
+		EndIf
+		
+		Local set:TMap=TMap(mungedScopes.ValueForKey( scope ))
+		If set
+			If set.Contains( munged.ToLower() )
+				Local id:Int=1
+				Repeat
+					id :+ 1
+					Local t$=munged+id
+					If set.Contains( t.ToLower() ) Continue
+					munged=t
+					Exit
+				Forever
+			End If
+		Else
+			If scope="$"
+				Print "OOPS2"
+				InternalErr
+			EndIf
+			set=New TMap
+			mungedScopes.Insert scope,set
+		End If
+		set.Insert munged.ToLower(), ""
+		decl.munged=munged
+	End Method
+End Rem
+
+
+
+	
+	Method Bra$( str$ )
+		If str.StartsWith( "(" ) And str.EndsWith( ")" )
+			Local n:Int=1
+			For Local i:Int=1 Until str.Length-1
+				Select str[i..i+1]
+				Case "("
+					n:+1
+				Case ")"
+					n:-1
+					If Not n Return "("+str+")"
+				End Select
+			Next
+			If n=1 Return str
+'			If str.FindLast("(")<str.Find(")") Return str
+		EndIf
+		Return "("+str+")"
+	End Method
+	
+	'Utility C/C++ style...
+	Method Enquote$( str$ )
+		Return LangEnquote( str )
+	End Method
+	
+	Method EscapeChars:String(str:String)
+		If str Then
+			Local found:Int = False
+			For Local i:Int = 0 Until str.length
+				If str[i] > 127 Then
+					found = True
+					Exit
+				End If
+			Next
+			
+			If Not found Then
+				Return str
+			End If
+		
+			Local s:String
+			
+			For Local i:Int = 0 Until str.length
+				Local char:Int = str[i]
+				
+				If char < 128 Then
+					s :+ Chr(char)
+				Else
+					s :+ "~~" + char + "~~"
+				End If
+			Next
+			
+			Return s
+		End If
+	End Method
+
+	Method TransUnaryOp$( op$ )
+		Select op
+		Case "+" Return "+"
+		Case "-" Return "-"
+		Case "~~" Return op
+		Case "not" Return "!"
+		End Select
+		InternalErr
+	End Method
+	
+	Method TransBinaryOp$( op$,rhs$ )
+'DebugLog "TransBinaryOp '" + op + "' : '" + rhs + "'"
+op = mapSymbol(op)
+		Select op
+		Case "+","-"
+			If rhs.StartsWith( op ) Return op+" "
+			Return op
+		Case "*","/" Return op
+		Case "shl" Return "<<"
+		Case "shr" Return ">>"
+		Case "sar" Return ">>"
+		Case "mod" Return " % "
+		Case "and" Return " && "
+		Case "or" Return " || "
+		Case "=" Return "=="
+		Case "<>" Return "!="
+		Case "<","<=",">",">=" Return op
+		Case "=<" Return "<="
+		Case "=>" Return ">="
+		Case "&","|" Return op
+		Case "~~" Return "^"
+		Case "<<", ">>" Return Op
+		Case "%" Return Op
+		End Select
+		InternalErr
+	End Method
+	
+	Method TransAssignOp$( op$ )
+op = mapSymbol(op)
+		Select op
+		Case ":mod" Return "%="
+		Case ":shl" Return "<<="
+		Case ":shr" Return ">>="
+		Case ":sar" Return ">>="
+		End Select
+		Return op
+	End Method
+	
+	Method ExprPri:Int( expr:TExpr )
+		'
+		'1=primary,
+		'2=postfix
+		'3=prefix
+		'
+		If TNewObjectExpr( expr )
+			Return 3
+		Else If TUnaryExpr( expr )
+			Select TUnaryExpr( expr ).op
+			Case "+","-","~~","not" Return 3
+			End Select
+			InternalErr
+		Else If TBinaryExpr( expr )
+			Select TBinaryExpr( expr ).op
+			Case "^" Return 4
+			Case "*","/","mod","%" Return 5
+			Case "+","-" Return 6
+			Case "shl","shr", "sar","<<", ">>" Return 7
+			Case "<","<=",">",">=", "=<", "=>" Return 8
+			Case "=","<>" Return 9
+			Case "&" Return 10
+			Case "~~" Return 11
+			Case "|" Return 12
+			Case "and" Return 13
+			Case "or" Return 14
+			End Select
+			InternalErr
+		EndIf
+		Return 2
+	End Method
+	
+	Method TransSubExpr$( expr:TExpr,pri:Int=2 )
+		Local t_expr$=expr.Trans()
+		'If expr.exprType._flags & TTYPE.T_VAR Then
+		'	t_expr = Bra("*" + t_expr)
+		'End If
+		If ExprPri( expr )>pri t_expr=Bra( t_expr )
+		Return t_expr
+	End Method
+	
+	Method TransExprNS$( expr:TExpr )
+		If TVarExpr( expr ) Return expr.Trans()
+		If TConstExpr( expr ) Return expr.Trans()
+		Return CreateLocal( expr )
+	End Method
+	
+	Method CreateLocal$( expr:TExpr, init:Int = True, vol:Int = True )
+		Local tmp:TLocalDecl=New TLocalDecl.Create( "",expr.exprType,expr, True, , vol )
+		MungDecl tmp
+		Emit TransLocalDecl( tmp,expr, True, init )+";"
+
+		EmitGDBDebug(_errInfo)
+		
+		Return tmp.munged
+	End Method
+
+	'***** Utility *****
+
+	Method TransLocalDecl$( decl:TLocalDecl,init:TExpr, declare:Int = False, outputInit:Int = True ) Abstract
+
+	Method TransGlobalDecl$( gdecl:TGlobalDecl ) Abstract
+	
+	Method EmitPushErr()
+	End Method
+	
+	Method EmitSetErr( errInfo$ )
+	End Method
+	
+	Method EmitPopErr()
+	End Method
+	
+	'***** Declarations *****
+	
+	Method TransGlobal$( decl:TGlobalDecl ) Abstract
+	
+	Method TransField$( decl:TFieldDecl,lhs:TExpr ) Abstract
+	
+	Method TransFunc$( decl:TFuncDecl,args:TExpr[],lhs:TExpr, sup:Int = False, scope:TScopeDecl = Null ) Abstract
+	
+	Method TransSuperFunc$( decl:TFuncDecl,args:TExpr[], scope:TScopeDecl ) Abstract
+	
+	
+	'***** Expressions *****
+	
+	Method TransConstExpr$( expr:TConstExpr ) Abstract
+	
+	Method TransNewObjectExpr$( expr:TNewObjectExpr ) Abstract
+	
+	Method TransNewArrayExpr$( expr:TNewArrayExpr ) Abstract
+	
+	Method TransSelfExpr$( expr:TSelfExpr ) Abstract
+	
+	Method TransCastExpr$( expr:TCastExpr ) Abstract
+	
+	Method TransUnaryExpr$( expr:TUnaryExpr ) Abstract
+	
+	Method TransBinaryExpr$( expr:TBinaryExpr ) Abstract
+	
+	Method TransIndexExpr$( expr:TIndexExpr ) Abstract
+	
+	Method TransSliceExpr$( expr:TSliceExpr ) Abstract
+	
+	Method TransArrayExpr$( expr:TArrayExpr ) Abstract
+	
+	Method TransArraySizeExpr$ ( expr:TArraySizeExpr ) Abstract
+	
+	Method TransIntrinsicExpr$( decl:TDecl,expr:TExpr,args:TExpr[]=Null ) Abstract
+	
+	Method TransArgs$( args:TExpr[],decl:TFuncDecl, objParam:String = Null ) Abstract
+
+	Method EmitDebugEnterScope(block:TBlockDecl) Abstract
+	
+	Method EmitLocalDeclarations(decl:TScopeDecl, v:TValDecl = Null) Abstract
+	
+	Method TransType$( ty:TType, ident:String, fpReturnTypeFunctionArgs:String = Null, fpReturnTypeClassFunc:Int = False) Abstract
+
+	Method TransObject:String(decl:TScopeDecl, this:Int = False) Abstract
+	
+	Method BeginLocalScope()
+		mungStack.Push mungScope
+		mungScope:TMap=New TMap'<TDecl>
+'		mungedScopes.Insert "$",New TMap
+		
+		If opt_debug Then
+			localScopeStack.Push localScope
+			localScope = New TStack
+		End If
+	End Method
+	
+	Method EndLocalScope()
+		mungScope=TMap(mungStack.Pop())
+'		mungedScopes.Insert "$",Null
+
+		If opt_debug Then
+			localScope = TStack(localScopeStack.Pop())
+		End If
+	End Method
+
+Rem	
+	Method MungMethodDecl( fdecl:TFuncDecl )
+
+		If fdecl.munged Return
+		
+		If fdecl.overrides
+			MungMethodDecl fdecl.overrides
+			fdecl.munged=fdecl.overrides.munged
+			Return
+		EndIf
+		
+		Local funcs:=funcMungs.Get( fdecl.ident )
+		If funcs
+			For Local tdecl:=EachIn funcs
+				If fdecl.EqualsArgs( tdecl )
+					fdecl.munged=tdecl.munged
+					Return
+				EndIf
+			Next
+		Else
+			funcs=New FuncDeclList
+			funcMungs.Set fdecl.ident,funcs
+		EndIf
+		
+		Local id:=fdecl.ident
+		If mungedFuncs.Contains( id )
+			Local n:=1
+			Repeat
+				n+=1
+				id=fdecl.ident+String(n)
+			Until Not mungedFuncs.Contains( id )
+		EndIf
+		
+		mungedFuncs.Set id,fdecl
+		fdecl.munged="p_"+id
+		funcs.AddLast fdecl
+	End
+End Rem	
+	'***** Simple statements *****
+	
+	'Expressions
+	Method TransStmtExpr$( expr:TStmtExpr )
+		Local t$=expr.stmt.Trans()
+		If t Emit t+";"
+		Return expr.expr.Trans()
+	End Method
+	
+	Method TransTemplateCast$( ty:TType,src:TType,expr$ )
+		Return expr
+	End Method
+	
+	Method TransVarExpr$( expr:TVarExpr )
+		Local decl:TVarDecl=TVarDecl( expr.decl.actual )
+
+		If decl.munged.StartsWith( "$" ) Return TransIntrinsicExpr( decl,Null )
+		
+		If TLocalDecl( decl ) Then
+			If decl.ty._flags & TType.T_VAR Then
+				Return "*" + decl.munged
+			Else
+				Return decl.munged
+			End If
+		End If
+		
+		If TFieldDecl( decl ) Return TransField( TFieldDecl( decl ),Null )
+		
+		If TGlobalDecl( decl ) Return TransGlobal( TGlobalDecl( decl ) )
+		
+		InternalErr
+	End Method
+	
+	Method TransMemberVarExpr$( expr:TMemberVarExpr )
+		Local decl:TVarDecl=TVarDecl( expr.decl.actual )
+		
+		If decl.munged.StartsWith( "$" ) Return TransIntrinsicExpr( decl,expr.expr )
+		
+		If TFieldDecl( decl ) Return TransField( TFieldDecl( decl ),expr.expr )
+
+		If TGlobalDecl( decl ) Return TransGlobal( TGlobalDecl( decl ) )
+
+		InternalErr
+	End Method
+	
+	Method TransInvokeExpr$( expr:TInvokeExpr )
+		Local decl:TFuncDecl=TFuncDecl( expr.decl.actual ),t$
+
+		If Not decl.munged Then
+			MungDecl decl
+		End If
+		
+		'If (decl.attrs & FUNC_PTR) And (decl.attrs & FUNC_INIT) And Not expr.InvokedWithBraces Return decl.munged
+		
+		'If ((decl.attrs & FUNC_PTR) Or (expr.decl.attrs & FUNC_PTR)) And Not expr.InvokedWithBraces Return decl.munged
+		
+		'If Not expr.InvokedWithBraces And expr.IsRhs Return decl.munged
+		
+		' if the call was a statement (even one written without parentheses), then invokedWithBraces is true
+		' so no complicated checks are needed here; if invokedWithBraces is false, this is definitely not a call
+		If Not expr.InvokedWithBraces Then Return decl.munged
+		
+		If decl.munged.StartsWith( "$" ) Return TransIntrinsicExpr( decl,Null,expr.args )
+		
+		If processingReturnStatement = 1 Then
+			If decl Then
+				processingReturnStatement :+ 1
+				Return CreateLocal(expr)
+			End If
+		Else
+			Return TransFunc( TFuncDecl(decl),expr.args,Null )
+		End If
+		
+		InternalErr
+	End Method
+	
+	Method TransInvokeMemberExpr$( expr:TInvokeMemberExpr )
+		Local decl:TFuncDecl=TFuncDecl( expr.decl.actual ),t$
+
+		If decl.munged.StartsWith( "$" ) Return TransIntrinsicExpr( decl,expr.expr,expr.args )
+		
+		If processingReturnStatement = 1 Then
+			If decl Then
+				processingReturnStatement :+ 1
+				Return CreateLocal(expr)
+			End If
+		Else
+			Return TransFunc( TFuncDecl(decl),expr.args,expr.expr )	
+		End If
+		
+		InternalErr
+	End Method
+	
+	Method TransInvokeSuperExpr$( expr:TInvokeSuperExpr )
+		Local decl:TFuncDecl=TFuncDecl( expr.origFuncDecl.actual ),t$
+
+		If decl.munged.StartsWith( "$" ) Return TransIntrinsicExpr( decl,expr )
+		
+		If processingReturnStatement = 1 Then
+			If decl Then
+				processingReturnStatement :+ 1
+				Return CreateLocal(expr)
+			End If
+		Else
+			If decl Return TransSuperFunc( TFuncDecl( expr.funcDecl ),expr.args, expr.classScope )
+		End If
+		
+		InternalErr
+	End Method
+	
+	Method TransFuncCallExpr:String( expr:TFuncCallExpr )
+
+		If TIndexExpr(expr.expr) And TArrayType(TIndexExpr(expr.expr).expr.exprType) And TFunctionPtrType(TArrayType(TIndexExpr(expr.expr).expr.exprType).elemType) Then
+			Local decl:TDecl = TFunctionPtrType(TArrayType(TIndexExpr(expr.expr).expr.exprType).elemType).func.actual
+			decl.Semant()
+			expr.args=expr.CastArgs( expr.args,TFuncDecl(decl) )
+			Return expr.expr.Trans() + TransArgs(expr.args, TFuncDecl(decl))
+		End If
+
+		' hmmm, complicated - a function returning and invoking a function pointer...		
+		If TInvokeExpr(expr.expr) And TFunctionPtrType(TInvokeExpr(expr.expr).exprType) Then
+			Local decl:TDecl = TFunctionPtrType(TInvokeExpr(expr.expr).exprType).func.actual
+			decl.Semant()
+			expr.args=expr.CastArgs( expr.args,TFuncDecl(decl) )
+			Return expr.expr.Trans() + TransArgs(expr.args, TFuncDecl(decl))
+		End If
+		
+		InternalErr
+	End Method
+	
+	Method TransExprStmt$( stmt:TExprStmt )
+		Return stmt.expr.TransStmt()
+	End Method
+	
+	Method TransAssignStmt$( stmt:TAssignStmt )
+		If stmt.rhs Return stmt.lhs.TransVar()+TransAssignOp(stmt.op)+stmt.rhs.Trans()
+		Return stmt.lhs.Trans()
+	End Method
+	
+	Method TransReturnStmt$( stmt:TReturnStmt )
+
+		Local t$="return"
+		unreachable=True
+		If stmt.expr Then
+
+			If TObjectType(stmt.expr.exprType) And TNullDecl(TObjectType(stmt.expr.exprType).classDecl) Then
+				If IsPointerType(stmt.fRetType, 0, TType.T_POINTER) Or IsNumericType(stmt.fRetType) Then
+					t:+ " 0"
+				End If
+				If TStringType(stmt.fRetType) Then
+					t:+ " &bbEmptyString"
+				End If
+				If TArrayType(stmt.fRetType) Then
+					t:+ " &bbEmptyArray"
+				End If
+
+			Else
+				
+				If TObjectType(stmt.expr.exprType) And TObjectType(stmt.expr.exprType).classDecl.IsStruct() And TConstExpr(stmt.expr) And Not TConstExpr(stmt.expr).value Then
+					Local lvar:String = CreateLocal(stmt.expr)
+					t :+ " " + lvar
+				Else
+
+					Local s:String
+					
+					' cast to function return type
+					If TObjectType(stmt.fRetType) Then
+						s :+ Bra(transObject(TObjectType(stmt.fRetType).classDecl))
+					End If
+
+					s :+ stmt.expr.Trans()
+					
+					' we have some temp variables that need to be freed before we can return
+					' put the results into a new variable, and return that.
+					If customVarStack.Count() > 0 Then
+						If Not TFunctionPtrType( stmt.expr.exprType ) Then
+							Emit TransType(stmt.expr.exprType, "rt_") + " rt_ = " + s + ";"
+						Else
+							Emit TransType(stmt.expr.exprType, "rt_") + " = " + s + ";"
+						End If
+						t:+ " rt_"
+					Else
+						t:+" " + s
+					End If
+				End If
+			End If
+			
+		End If
+
+		FreeVarsIfRequired()
+		
+		' if this is a Delete() method, we need to call the dtor first
+		Local funcScope:TFuncDecl = _env.FuncScope()
+		If funcScope And funcScope.IdentLower() = "delete" Then
+			Local classScope:TClassDecl = funcScope.ClassScope()
+			If classScope Then
+				EmitClassDeclDeleteDtor(classScope)
+			End If
+		End If
+		
+		Return t
+	End Method
+	
+	Method NextExitId:Int(bc:TTryBreakCheck)
+		If Not bc.exitId Then
+			exitLabelId :+ 1
+			bc.exitId = exitLabelId
+		End If
+		
+		Return bc.exitId
+	End Method
+
+	Method NextContId:Int(bc:TTryBreakCheck)
+		If Not bc.contId Then
+			contLabelId :+ 1
+			bc.contId = contLabelId
+		End If
+		
+		Return bc.contId
+	End Method
+	
+	Method TransContinueStmt$( stmt:TContinueStmt )
+		Local returnStr:String
+		
+		Local contLoop:TStmt
+		' if we are continuing with a loop label, we'll need to find it in the stack
+		If stmt.label And TLoopLabelExpr(stmt.label) Then
+			contLoop = TLoopLabelExpr(stmt.label).loop
+		End If
+		' get Try statements in the stack in this loop
+		Local tryStmts:TTryStmt[] = LoopTryStmts(contLoop)
+		Local count:Int = tryStmts.length
+		Local nowUnreachable:Int = False
+		If count > 0 Then
+			Local bc:TTryBreakCheck = GetTopLoop(contLoop)
+			If bc Then
+				NextContId(bc)
+				For Local i:Int = 0 Until count
+					Emit "bbExLeave();"
+					If opt_debug Then Emit "bbOnDebugPopExState();"
+					If tryStmts[i].finallyStmt Then
+						Local returnLabelDecl:TLoopLabelDecl = New TLoopLabelDecl.Create("continue")
+						MungDecl returnLabelDecl
+						EmitFinallyJmp tryStmts[i].finallyStmt, returnLabelDecl
+						Emit TransLabel(returnLabelDecl)
+					End If
+				Next
+				Emit "goto " + TransLabelCont(bc, False)
+			Else
+				InternalErr
+			End If
+		Else
+		 	' For debug builds, we need to rollback the local scope stack correctly
+			count = 0
+			
+			If opt_debug And TLoopStmt(contLoop) And Not TLoopStmt(contLoop).block.IsNoDebug() Then
+				count = LoopLocalScopeDepth(contLoop)
+			End If
+			
+			If count > 0 Then
+				Local bc:TTryBreakCheck = GetTopLocalLoop(contLoop)
+				If bc Then
+					NextContId(bc)
+					For Local i:Int = 0 Until count
+						Emit "bbOnDebugLeaveScope();"
+					Next
+					Emit "goto " + TransLabelCont(bc, False)
+				Else
+					InternalErr
+				End If
+			Else
+				If opt_debug And stmt.loop And Not stmt.loop.block.IsNoDebug() Then
+					count = LoopLocalScopeDepth(Null)
+				End If
+				For Local i:Int = 0 Until count
+					Emit "bbOnDebugLeaveScope();"
+				Next
+				
+				' No Try statements in the stack here..
+				If stmt.label And TLoopLabelExpr(stmt.label) Then
+					Emit "goto " + TransLoopLabelCont(TLoopLabelExpr(stmt.label).loop.loopLabel.realIdent, False)
+				Else
+					returnStr = "continue"
+				End If
+			End If
+		End If
+		
+		unreachable = True
+		Return returnStr
+	End Method
+	
+	Method TransBreakStmt$( stmt:TBreakStmt )
+		Local returnStr:String
+		
+		Local brkLoop:TStmt
+		' if we are exiting with a loop label, we'll need to find it in the stack
+		If stmt.label And TLoopLabelExpr(stmt.label) Then
+			brkLoop = TLoopLabelExpr(stmt.label).loop
+		End If
+		' get Try statements in the stack in this loop
+		Local tryStmts:TTryStmt[] = LoopTryStmts(brkLoop)
+		Local count:Int = tryStmts.length
+		Local nowUnreachable:Int = False
+		If count > 0 Then
+			Local bc:TTryBreakCheck = GetTopLoop(brkLoop)
+			If bc Then
+				NextExitId(bc)
+				For Local i:Int = 0 Until count
+					Emit "bbExLeave();"
+					If opt_debug Then Emit "bbOnDebugPopExState();"
+					If tryStmts[i].finallyStmt Then
+						Local returnLabelDecl:TLoopLabelDecl = New TLoopLabelDecl.Create("break")
+						MungDecl returnLabelDecl
+						EmitFinallyJmp tryStmts[i].finallyStmt, returnLabelDecl
+						Emit TransLabel(returnLabelDecl)
+					End If
+				Next
+				Emit "goto " + TransLabelExit(bc, False)
+			Else
+				InternalErr
+			End If
+		Else
+		 	' For debug builds, we need to rollback the local scope stack correctly
+			count = 0
+			
+			If opt_debug And TLoopStmt(brkLoop) And Not TLoopStmt(brkLoop).block.IsNoDebug() Then
+				count = LoopLocalScopeDepth(brkLoop)
+			End If
+			
+			If count > 0 Then
+				Local bc:TTryBreakCheck = GetTopLocalLoop(brkLoop)
+				If bc Then
+					NextExitId(bc)
+					For Local i:Int = 0 Until count
+						Emit "bbOnDebugLeaveScope();"
+					Next
+					Emit "goto " + TransLabelExit(bc, False)
+				Else
+					InternalErr
+				End If
+			Else
+				If opt_debug And stmt.loop And Not stmt.loop.block.IsNoDebug() Then
+					count = LoopLocalScopeDepth(Null)
+				End If
+				For Local i:Int = 0 Until count
+					Emit "bbOnDebugLeaveScope();"
+				Next
+				
+				' No Try statements in the stack here..
+				If stmt.label And TLoopLabelExpr(stmt.label) Then
+					Emit "goto " + TransLoopLabelExit(TLoopLabelExpr(stmt.label).loop.loopLabel.realIdent, False)
+				Else
+					returnStr = "break"
+				End If
+			End If
+		End If
+		
+		unreachable = True
+		broken :+ 1
+		Return returnStr
+	End Method
+	
+	Method TransTryStmt$( stmt:TTryStmt )
+	End Method
+	
+	Method EmitFinallyJmp(stmt:TFinallyStmt, returnLabel:TLoopLabelDecl) Abstract
+	
+	Method TransThrowStmt$( stmt:TThrowStmt )
+	End Method
+
+	Method TransBuiltinExpr$( expr:TBuiltinExpr )
+		If TMinExpr(expr) Return TransMinExpr(TMinExpr(expr))
+		If TMaxExpr(expr) Return TransMaxExpr(TMaxExpr(expr))
+		If TAbsExpr(expr) Return TransAbsExpr(TAbsExpr(expr))
+		If TAscExpr(expr) Return TransAscExpr(TAscExpr(expr))
+		If TChrExpr(expr) Return TransChrExpr(TChrExpr(expr))
+		If TSgnExpr(expr) Return TransSgnExpr(TSgnExpr(expr))
+		If TLenExpr(expr) Return TransLenExpr(TLenExpr(expr))
+		If TSizeOfExpr(expr) Return TransSizeOfExpr(TSizeOfExpr(expr))
+		Err "TODO : TransBuiltinExpr()"
+	End Method
+	
+	Method TransMinExpr:String(expr:TMinExpr)
+	End Method
+
+	Method TransMaxExpr:String(expr:TMaxExpr)
+	End Method
+
+	Method TransAbsExpr:String(expr:TAbsExpr)
+	End Method
+
+	Method TransAscExpr:String(expr:TAscExpr)
+	End Method
+
+	Method TransChrExpr:String(expr:TChrExpr)
+	End Method
+
+	Method TransSgnExpr:String(expr:TSgnExpr)
+	End Method
+
+	Method TransLenExpr:String(expr:TLenExpr)
+	End Method
+
+	Method TransSizeOfExpr:String(expr:TSizeOfExpr)
+	End Method
+	
+	Method TransIdentTypeExpr:String(expr:TIdentTypeExpr) Abstract
+	
+	Method TransLabelCont:String(bc:TTryBreakCheck, jmp:Int = True)
+		If jmp Then
+			Return "_contjmp" + bc.contId + ": ;"
+		Else
+			Return "_contjmp" + bc.contId + ";"
+		End If
+	End Method
+	
+	Method TransLabelExit:String(bc:TTryBreakCheck, jmp:Int = True)
+		If jmp Then
+			Return "_exitjmp" + bc.exitId + ": ;"
+		Else
+			Return "_exitjmp" + bc.exitId + ";"
+		End If
+	End Method
+
+	Method TransLoopLabelCont:String(id:String, jmp:Int = True)
+		If jmp Then
+			Return "_loopcont_" + id.ToLower() + ": ;"
+		Else
+			Return "_loopcont_" + id.ToLower() + ";"
+		End If
+	End Method
+
+	Method TransLoopLabelExit:String(id:String, jmp:Int = True)
+		If jmp Then
+			Return "_loopexit_" + id.ToLower() + ": ;"
+		Else
+			Return "_loopexit_" + id.ToLower() + ";"
+		End If
+	End Method
+	
+	Method TransLabel:String(labelDecl:TLoopLabelDecl)
+		Return labelDecl.munged + ":;"
+	End Method
+
+	'***** Block statements - all very C like! *****
+	
+	Method Emit( t$, useIndent:Int = True )
+		If Not t Return
+		If useIndent
+			If t.StartsWith( "}" )
+				indent=indent[..indent.Length-1]
+			EndIf
+		End If
+		LINES.AddLast indent+t
+		'code+=indent+t+"~n"
+		If useIndent
+			If t.EndsWith( "{" )
+				indent:+"~t"
+			EndIf
+		End If
+	End Method
+	
+	Method JoinLines$( file:String )
+		Local _lines:TStringList = TStringList(outputFiles.ValueForKey(file))
+		
+		Local code$=_lines.Join( "~n" )
+		_lines.Clear
+		Return code
+	End Method
+	
+	'returns and resets unreachable status
+	Method EmitBlock:Int( block:TBlockDecl )
+		Local stmtCount:Int
+'DebugStop
+		'If ENV_CONFIG="debug"
+		'	If TFuncDecl( block ) EmitPushErr
+		'EndIf
+
+
+		PushEnv block
+		
+		' enter scope
+		If opt_debug And Not block.IsNoDebug() And Not block.generated Then
+			PushLoopLocalStack(block)
+			EmitDebugEnterScope(block)
+		End If
+
+		For Local stmt:TStmt=EachIn block.stmts
+		
+			_errInfo=stmt.errInfo
+			
+			If unreachable
+				' Statements following cannot be reached - maybe we have Returned, etc
+				' So don't process any more for this block - they won't be generated now!
+				Exit
+			EndIf
+
+Rem
+			If ENV_CONFIG="debug"
+				Local rs:TReturnStmt=TReturnStmt( stmt )
+				If rs
+					If rs.expr
+						EmitSetErr stmt.errInfo
+						Local t_expr$=TransExprNS( rs.expr )
+						EmitPopErr
+						Emit "return "+t_expr+";"
+					Else
+						EmitPopErr
+						Emit "return;"
+					EndIf
+					unreachable=True
+					Continue
+				EndIf
+				EmitSetErr stmt.errInfo
+			EndIf
+End Rem
+			If opt_debug And Not block.IsNoDebug() Then
+				' only for user-made code
+				If Not stmt.generated Then
+					EmitDebugStmtErrInfo(stmt.errInfo, stmtCount)
+					stmtCount :+ 1
+				End If
+			
+			End If
+
+			EmitGDBDebug(stmt)
+			
+			If TReturnStmt(stmt) And Not tryStack.IsEmpty() Then
+				processingReturnStatement = 1
+			End If
+			
+			Local t$=stmt.Trans()
+			
+			processingReturnStatement = 0
+			
+			If opt_debug And Not block.IsNoDebug() Then
+				If TReturnStmt(stmt) Then
+					For Local b:TBlockDecl = EachIn localScope
+						Emit "bbOnDebugLeaveScope();"
+					Next
+				End If
+			End If
+			
+			If TReturnStmt(stmt) Then
+				For Local tryStmt:TTryStmt = EachIn tryStack
+					Emit "bbExLeave();"
+					If opt_debug Then Emit "bbOnDebugPopExState();"
+					If tryStmt.finallyStmt Then
+						Local returnLabelDecl:TLoopLabelDecl = New TLoopLabelDecl.Create("return")
+						MungDecl returnLabelDecl
+						EmitFinallyJmp tryStmt.finallyStmt, returnLabelDecl
+						Emit TransLabel(returnLabelDecl)
+					End If
+				Next
+			End If
+			
+			If t Emit t+";"
+
+			If DEBUG And debugOut Then
+				Emit debugOut
+				debugOut = Null
+			End If
+			
+			Local v:String = String(customVarStack.Pop())
+			While v
+				Emit "bbMemFree" + Bra(v) + ";"
+				v = String(customVarStack.Pop())
+			Wend
+			
+		Next
+
+		If opt_debug And Not block.IsNoDebug() And Not block.generated Then
+			PopLoopLocalStack()
+			If Not unreachable Then
+				Emit "bbOnDebugLeaveScope();"
+			End If
+		End If
+
+		Local r:Int=unreachable
+		unreachable=False
+		PopEnv
+		Return r
+	End Method
+	
+	Method TransDeclStmt$( stmt:TDeclStmt, declare:Int = False )
+		Local decl:TLocalDecl=TLocalDecl( stmt.decl )
+		If decl
+			MungDecl decl
+			' only generate local declarations once.
+			If decl.generated Then
+				If Not decl.done Then
+					decl.done = True
+				Else
+					Return ""
+				End If
+			End If
+			Return TransLocalDecl( decl,decl.init, decl.generated Or declare )
+		EndIf
+		Local cdecl:TConstDecl=TConstDecl( stmt.decl )
+		If cdecl
+			Return Null
+		EndIf
+		Local gdecl:TGlobalDecl=TGlobalDecl( stmt.decl )
+		If gdecl Then
+			MungDecl gdecl
+			If gdecl.inited Return Null
+			Return TransGlobalDecl( gdecl )
+		End If
+		InternalErr
+	End Method
+	
+	Method TransIfStmt$( stmt:TIfStmt )
+		If TConstExpr( stmt.expr )
+			If TConstExpr( stmt.expr ).value
+				Emit "{"
+				EmitLocalDeclarations(stmt.thenBlock)
+				If EmitBlock( stmt.thenBlock ) unreachable=True
+				Emit "}"
+			Else If stmt.elseBlock.stmts.First()
+				Emit "{"
+				EmitLocalDeclarations(stmt.elseBlock)
+				If EmitBlock( stmt.elseBlock ) unreachable=True
+				Emit "}"
+			EndIf
+		Else If stmt.elseBlock.stmts.First()
+			Emit "if"+Bra( stmt.expr.Trans() )+"{"
+			EmitLocalDeclarations(stmt.thenBlock)
+			FreeVarsIfRequired(False)
+			PushVarScope
+			Local unr:Int=EmitBlock( stmt.thenBlock )
+			PopVarScope
+			Emit "}else{"
+			EmitLocalDeclarations(stmt.elseBlock)
+			FreeVarsIfRequired
+			Local unr2:Int=EmitBlock( stmt.elseBlock )
+			Emit "}"
+			If unr And unr2 unreachable=True
+		Else
+
+'			Emit "if"+ Bra(TransCondition(stmt.expr)) + "{"
+'			If TVarExpr(stmt.expr) Then
+'				If TObjectType(TVarExpr(stmt.expr).exprType) Then
+'					Emit "if"+Bra( stmt.expr.Trans() + "!= &bbNullObject") + "{"
+'				Else If TStringType(TVarExpr(stmt.expr).exprType)  Then
+'					Emit "if"+Bra( stmt.expr.Trans() + "!= &bbEmptyString") + "{"
+'				Else
+'					Emit "if"+Bra( stmt.expr.Trans() )+"{"
+'				End If
+'			Else
+				Emit "if"+Bra( stmt.expr.Trans() )+"{"
+				FreeVarsIfRequired(False)
+'			End If
+			EmitLocalDeclarations(stmt.thenBlock)
+			PushVarScope
+			Local unr:Int=EmitBlock( stmt.thenBlock )
+			PopVarScope
+			Emit "}"
+			FreeVarsIfRequired
+		EndIf
+	End Method
+	
+	Method FreeVarsIfRequired(removeFromStack:Int = True)
+		If removeFromStack
+			Local v:String = String(customVarStack.Pop())
+			While v
+				Emit "bbMemFree" + Bra(v) + ";"
+				v = String(customVarStack.Pop())
+			Wend
+		Else
+			For Local v:String = EachIn customVarStack
+				Emit "bbMemFree" + Bra(v) + ";"
+			Next
+		End If
+	End Method
+	
+'	Method TransCondition:String(expr:TExpr)
+'		If TVarExpr(expr) Then
+'			If TObjectType(TVarExpr(expr).exprType) Then
+'				Return Bra( expr.Trans() + "!= &bbNullObject")
+'			Else If TStringType(TVarExpr(expr).exprType)  Then
+'				Return Bra( expr.Trans() + "!= &bbEmptyString")
+'			Else
+'				Return Bra( expr.Trans() )
+'			End If
+'		Else
+'			Return Bra( expr.Trans() )
+'		End If
+'	End Method
+	
+	Method TransWhileStmt$( stmt:TWhileStmt )
+		Local nbroken:Int=broken
+
+		Emit "while"+Bra( stmt.expr.Trans() )+"{"
+		
+		Local check:TTryBreakCheck = New TTryBreakCheck
+		check.stmt = stmt
+		PushLoopTryStack(check)
+		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
+			PushLoopLocalStack(check)
+		End If
+		EmitLocalDeclarations(stmt.block)
+		Local unr:Int=EmitBlock( stmt.block )
+		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
+			PopLoopLocalStack
+		End If
+		PopLoopTryStack
+		
+		If check.contId Then
+			Emit TransLabelCont(check)
+		End If
+
+		If stmt.loopLabel Then
+			MungDecl stmt.loopLabel
+			Emit TransLoopLabelCont(stmt.loopLabel.realIdent, True)
+		End If
+		
+		Emit "}"
+
+		If check.exitId Then
+			Emit TransLabelExit(check)
+		End If
+
+		If stmt.loopLabel Then
+			Emit TransLoopLabelExit(stmt.loopLabel.realIdent, True)
+		End If
+		
+		If broken=nbroken And TConstExpr( stmt.expr ) And TConstExpr( stmt.expr ).value unreachable=True
+		broken=nbroken
+	End Method
+
+	Method TransRepeatStmt$( stmt:TRepeatStmt )
+		Local nbroken:Int=broken
+
+		SetOutputTemp()
+
+		Emit "do{"
+		
+		Local check:TTryBreakCheck = New TTryBreakCheck
+		check.stmt = stmt
+		PushLoopTryStack(check)
+		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
+			PushLoopLocalStack(check)
+		End If
+		EmitLocalDeclarations(stmt.block)
+		Local unr:Int=EmitBlock( stmt.block )
+		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
+			PopLoopLocalStack
+		End If
+		PopLoopTryStack
+
+		If check.contId Then
+			Emit TransLabelCont(check)
+		End If
+
+		If stmt.loopLabel Then
+			MungDecl stmt.loopLabel
+			Emit TransLoopLabelCont(stmt.loopLabel.realIdent, True)
+		End If
+		
+		SetOutput("source")
+
+		Local s:String = "}while(!"+Bra( stmt.expr.Trans() )+");"
+		
+		SetOutputTemp(True)
+		
+		Emit s
+
+		If check.exitId Then
+			Emit TransLabelExit(check)
+		End If
+
+		If stmt.loopLabel Then
+			Emit TransLoopLabelExit(stmt.loopLabel.realIdent, True)
+		End If
+
+		If broken=nbroken And TConstExpr( stmt.expr ) And Not TConstExpr( stmt.expr ).value unreachable=True
+		broken=nbroken
+	End Method
+
+	Method TransForStmt$( stmt:TForStmt )
+		Local nbroken:Int=broken
+
+		Local init$
+
+		Local decl:Int
+		Local vdecl:TValDecl
+		If TDeclStmt(stmt.init) Then
+			decl = True
+			Emit "{"
+			Emit TransDeclStmt(TDeclStmt(stmt.init), True) + ";"
+			'init = TDeclStmt(stmt.init).decl.munged
+			vdecl = TValDecl(TDeclStmt(stmt.init).decl)
+		Else
+			init=stmt.init.Trans()
+		End If
+		Local expr$=stmt.expr.Trans()
+		Local incr$=stmt.incr.Trans()
+
+		Emit "for("+init+";"+expr+";"+incr+"){"
+
+		Local check:TTryBreakCheck = New TTryBreakCheck
+		check.stmt = stmt
+		PushLoopTryStack(check)
+		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
+			PushLoopLocalStack(check)
+		End If
+		EmitLocalDeclarations(stmt.block, vdecl)
+		Local unr:Int=EmitBlock( stmt.block )
+		If opt_debug And Not stmt.block.IsNoDebug() And Not stmt.block.generated Then
+			PopLoopLocalStack
+		End If
+		PopLoopTryStack
+		
+		If check.contId Then
+			Emit TransLabelCont(check)
+		End If
+
+		If stmt.loopLabel Then
+			MungDecl stmt.loopLabel
+			Emit TransLoopLabelCont(stmt.loopLabel.realIdent, True)
+		End If
+		
+		Emit "}"
+		
+		If decl Then
+			Emit "}"
+		End If
+
+		If check.exitId Then
+			Emit TransLabelExit(check)
+		End If
+
+		If stmt.loopLabel Then
+			Emit TransLoopLabelExit(stmt.loopLabel.realIdent, True)
+		End If
+		
+		If broken=nbroken And TConstExpr( stmt.expr ) And TConstExpr( stmt.expr ).value unreachable=True
+		broken=nbroken
+	End Method
+
+	Method TransAssertStmt$( stmt:TAssertStmt ) Abstract
+
+	Method TransEndStmt$( stmt:TEndStmt ) Abstract
+
+	Method TransReleaseStmt$( stmt:TReleaseStmt ) Abstract
+
+	Method TransRestoreDataStmt$( stmt:TRestoreDataStmt ) Abstract
+
+	Method TransReadDataStmt$( stmt:TReadDataStmt ) Abstract
+	
+	Method TransNativeStmt$( stmt:TNativeStmt) Abstract
+
+	'module
+	Method TransApp( app:TAppDecl ) Abstract
+
+Rem	
+	Method MungOverrides( cdecl:TClassDecl )
+		For Local decl:=Eachin cdecl.Semanted
+			Local fdecl:=TFuncDecl( decl )
+			If fdecl And fdecl.overrides
+				If Not fdecl.overrides.munged InternalErr
+				fdecl.munged=fdecl.overrides.munged
+				mungScope.Insert fdecl.munged,fdecl
+			Endif
+		Next
+	End
+End Rem
+	
+	Method PostProcess$( source$ ) 
+		Return source
+	End Method
+	
+	Method SetOutput( file:String )
+		Local _lines:TStringList = TStringList(outputFiles.ValueForKey(file))
+		
+		If Not _lines Then
+			_lines = New TStringList
+			outputFiles.Insert(file, _lines)
+		End If
+		
+		LINES = _lines
+		
+	End Method
+
+	Method SetOutputTemp( fin:Int = False )
+		Global tmpLevel:Int = 0
+	
+		If Not fin Then
+			tmpLevel :+ 1
+
+			Local _lines:TStringList = New TStringList
+			outputFiles.Insert("tmp" + tmpLevel, _lines)
+	
+			LINES = _lines
+		Else
+			Local _lines:TStringList = TStringList(outputFiles.ValueForKey("tmp" + tmpLevel))
+			
+			tmpLevel :- 1
+		
+			If Not tmpLevel Then
+				SetOutput("source")
+			Else
+				LINES = TStringList(outputFiles.ValueForKey("tmp" + tmpLevel))
+			End If
+			
+			If _lines Then
+				For Local line:String = EachIn _lines
+					LINES.AddLast(line)
+				Next
+			End If
+			
+		End If
+	End Method
+
+	Method DebugPrint(text:String, func:String = Null, trans:Int = False)
+		Global count:Int
+		Global lastFunc:String
+		
+		If func Then
+			lastFunc = func
+		End If
+		
+		Local s:String = "fprintf(stderr," + "~q" + lastFunc + " : " + count + " :: " + text + "\n~q)" + ";fflush(stderr);"
+		
+		If trans Then
+			debugOut :+ indent + s + "~n"
+		Else
+			Emit s
+		End If
+		count :+ 1
+	End Method
+	
+	Method DebugString(s:String, func:String = Null, trans:Int = False)
+		' bbNullObject test
+		If trans Then
+			debugOut :+ indent + "if (" + s + "==&bbNullObject) {~n"
+		Else
+			Emit "if (" + s + "==&bbNullObject) {"
+		End If
+		DebugPrint("Invalid Null String : " + s, func, trans)
+		If trans Then
+			debugOut :+ indent + "}~n"
+		Else
+			Emit "}"
+		End If
+	End Method
+
+	Method DebugArray(s:String, func:String = Null, trans:Int = False)
+		' bbNullObject test
+		If trans Then
+			debugOut :+ indent + "if (" + s + "==&bbNullObject) {~n"
+		Else
+			Emit "if (" + s + "==&bbNullObject) {"
+		End If
+		DebugPrint("Invalid Null Array : " + s, func, trans)
+		If trans Then
+			debugOut :+ indent + "}~n"
+		Else
+			Emit "}"
+		End If
+	End Method
+
+	Method DebugObject(ty:TType, id:String, func:String = Null, trans:Int = False)
+		If TObjectType(ty) Or TStringType(ty) Or TArrayType(ty) Then
+			' null test
+			If trans Then
+				debugOut :+ indent + "if (" + id + "==NULL) {~n"
+			Else
+				Emit "if (" + id + "==NULL) {"
+			End If
+			DebugPrint("Null Pointer : " + id, func, trans)
+			If trans Then
+				If ABORT_ON_NULL Then
+					debugOut :+ indent + "abort();~n"
+				End If
+				debugOut :+ indent + "}~n"
+			Else
+				If ABORT_ON_NULL Then
+					Emit "abort();~n"
+				End If
+				Emit "}"
+			End If
+		End If
+		
+		If TStringType(ty) Then
+			DebugString(id, func, trans)
+		Else If TArrayType(ty) Then
+			DebugArray(id, func, trans)
+		End If
+	End Method
+	
+	Method EmitDebugStmtErrInfo(info:String, count:Int)
+		' extract from info
+		info = info[1..info.length-1]
+		Local infoArray:String[] = info.Split(";")
+
+		Local dbg:String = "struct BBDebugStm __stmt_" + count + " = {"
+		dbg :+ Enquote(infoArray[0]) + ", "
+		dbg :+ infoArray[1] + ", "
+		dbg :+ infoArray[2] + "};"
+		Emit dbg
+		Emit "bbOnDebugEnterStm(&__stmt_" + count + ");" 
+	End Method
+	
+	Method EmitGDBDebug(obj:Object)
+		If opt_gdbdebug Then
+			If TStmt(obj) Then
+				Local stmt:TStmt = TStmt(obj)
+				Local infoArray:String[] = stmt.errInfo[1..stmt.errInfo.length-1].Split(";")
+				If Not stmt.generated Then
+					Emit "#line " + infoArray[1] + " " + Enquote(infoArray[0])
+				End If
+			Else If TDecl(obj) Then
+				Local decl:TDecl = TDecl(obj)
+				Local infoArray:String[] = decl.errInfo[1..decl.errInfo.length-1].Split(";")
+				Emit "#line " + infoArray[1] + " " + Enquote(infoArray[0])
+			Else If String(obj) Then
+				Local errInfo:String = String(obj)
+				Local infoArray:String[] = errInfo[1..errInfo.length-1].Split(";")
+				Emit "#line " + infoArray[1] + " " + Enquote(infoArray[0])
+			End If
+		End If
+	End Method
+	
+	Method EmitClassDeclDeleteDtor( classDecl:TClassDecl )
+	End Method
+	
+End Type
+
+Type TTryBreakCheck
+
+	Field contId:Int
+	Field exitId:Int
+
+	Field stmt:TStmt
+	
+End Type

部分文件因为文件数量过多而无法显示