浏览代码

Merge remote-tracking branch 'remotes/official/master' into finally

# Conflicts:
#	ctranslator.bmx
#	parser.bmx
#	translator.bmx
HurryStarfish 7 年之前
父节点
当前提交
3bec54518f
共有 18 个文件被更改,包括 949 次插入639 次删除
  1. 1 1
      base.stringhelper.bmx
  2. 1 1
      base64.bmx
  3. 3 1
      bcc.bmx
  4. 481 471
      config.bmx
  5. 39 15
      ctranslator.bmx
  6. 191 87
      decl.bmx
  7. 75 8
      expr.bmx
  8. 1 1
      iparser.bmx
  9. 2 2
      options.bmx
  10. 99 24
      parser.bmx
  11. 11 2
      stmt.bmx
  12. 1 1
      stringbuffer_common.bmx
  13. 1 1
      stringbuffer_core.bmx
  14. 1 1
      stringbuffer_glue.c
  15. 2 2
      toker.bmx
  16. 1 1
      transform.c
  17. 5 1
      translator.bmx
  18. 34 19
      type.bmx

+ 1 - 1
base.stringhelper.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2014-2017 Bruce A Henderson
+' Copyright (c) 2014-2018 Bruce A Henderson
 ' Copyright (c) 2014-2017 Ronny Otto
 ' Copyright (c) 2014-2017 Ronny Otto
 '
 '
 ' This software is provided 'as-is', without any express or implied
 ' This software is provided 'as-is', without any express or implied

+ 1 - 1
base64.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2008-2017 Bruce A Henderson
+' Copyright (c) 2008-2018 Bruce A Henderson
 ' 
 ' 
 ' Permission is hereby granted, free of charge, to any person obtaining a copy
 ' Permission is hereby granted, free of charge, to any person obtaining a copy
 ' of this software and associated documentation files (the "Software"), to deal
 ' of this software and associated documentation files (the "Software"), to deal

+ 3 - 1
bcc.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 '
 '
@@ -47,6 +47,8 @@ If opt_buildtype = BUILDTYPE_MODULE Then
 	End If
 	End If
 End If
 End If
 
 
+TGenProcessor.processor = New TParser
+
 Local app:TAppDecl 
 Local app:TAppDecl 
 Local trans:TCTranslator 
 Local trans:TCTranslator 
 Try
 Try

+ 481 - 471
config.bmx

@@ -1,471 +1,481 @@
-' Copyright (c) 2013-2017 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.
-'
-SuperStrict
-
-Import BRL.LinkedList
-Import BRL.Map
-Import BRL.FileSystem
-Import Pub.zlib
-
-Import "options.bmx"
-Import "base.stringhelper.bmx"
-Import "base64.bmx"
-
-' debugging help
-Const DEBUG:Int = False
-Const ABORT_ON_NULL:Int = True
-Const PROFILER:Int = False
-Const DEBUGSTOP_ON_ERROR:Int = False
-
-Global ENV_LANG$
-
-Global _errInfo$
-Global _errStack:TList = New TList
-
-' bytes offset to the first field
-Global OBJECT_BASE_OFFSET:Int = 8
-' 4 bytes on 32-bit, 8 bytes on 64-bit
-Global POINTER_SIZE:Int = 4
-
-Global _symbols$[]=[ "..","[]",":*",":/",":+",":-",":|",":&",":~~",":shr",":shl",":sar",":mod"]
-Global _symbols_map$[]=[ "..","[]","*=","/=","+=","-=","|=","&=","^=",">>=", "<<=",">>=","%=" ]
-
-Function PushErr( errInfo$ )
-	_errStack.AddLast _errInfo
-	_errInfo=errInfo
-End Function
-
-Function PopErr()
-	_errInfo=String(_errStack.RemoveLast())
-End Function
-
-Function Err( err$ )
-	If DEBUGSTOP_ON_ERROR Then
-		DebugStop ' useful for debugging!
-	End If
-	Throw "Compile Error: "+err + "~n" + _errInfo + "~n"
-End Function
-
-Function Warn( err$ )
-	'If DEBUGSTOP_ON_ERROR Then
-	'	DebugStop ' useful for debugging!
-	'End If
-	Print "Compile Warning: "+err + "~n" + _errInfo + "~n"
-End Function
-
-Function FormatError:String(path:String, line:Int, char:Int)
-	Return "[" + path + ";" + line + ";" + char + "]"
-End Function
-
-Function InternalErr()
-	If DEBUGSTOP_ON_ERROR Then
-		DebugStop ' useful for debugging!
-	End If
-	Throw "Internal Error.~n" + _errInfo + "~n"
-End Function
-
-Function IsSpace:Int( ch:Int )
-	Return ch<=Asc(" ") Or ch=$A0 ' NO-BREAK SPACE (U+00A0)
-End Function
-
-Function IsDigit:Int( ch:Int )
-	Return ch>=Asc("0") And ch<=Asc("9")
-End Function
-
-Function IsAlpha:Int( ch:Int )
-	Return (ch>=Asc("A") And ch<=Asc("Z")) Or (ch>=Asc("a") And ch<=Asc("z"))
-End Function
-
-Function IsBinDigit:Int( ch:Int )
-	Return ch=Asc("0") Or ch=Asc("1")
-End Function
-
-Function IsHexDigit:Int( ch:Int )
-	Return IsDigit(ch) Or (ch>=Asc("A") And ch<=Asc("F")) Or (ch>=Asc("a") And ch<=Asc("f"))
-End Function
-
-Function Todo() 
-	Err "TODO!"
-End Function
-
-Function IsStandardFunc:Int(func:String)
-	func = func.ToLower()
-	
-	Global funcs:String = ";isalnum;isalpha;isascii;isblank;iscntrl;isdigit;isgraph;islower;isprint;ispunct;isspace;isupper;isxdigit;" + ..
-		"strlen;_wgetenv;_wputenv;"
-	
-	Return funcs.Find(func) > 0
-End Function
-
-Function mapSymbol:String(sym:String)
-	For Local i:Int = 0 Until _symbols.length
-		If sym = _symbols[i] Then
-			Return _symbols_map[i]
-		End If
-	Next
-	Return sym
-End Function
-
-
-'enquote depending on ENV_LANG
-'
-Function LangEnquote$( str$ )
-	str=EscapeString(str)
-'	str=str.Replace( "~0","\0" )	'Fix me?
-	For Local i:Int=0 Until str.Length
-		If str[i]>=32 And str[i]<128 Continue
-		Local t$,n:Int=str[i]
-		While n
-			Local c:Int=(n&15)+48
-			If c>=58 c:+97-58
-			t=Chr( c )+t
-			n=(n Shr 4) & $0fffffff
-		Wend
-		If Not t t="0"
-		If ENV_LANG = "cpp" Then
-		'Case "cpp"
-			t="~q~q\x"+t+"~q~q"
-		Else
-			t="\u"+("0000"+t)[-4..]
-		End If
-		str=str[..i]+t+str[i+1..]
-		i:+t.Length-1
-	Next
-	str="~q"+str+"~q"
-	If ENV_LANG="cpp" str="L"+str
-	Return str
-End Function
-
-Function EscapeString$(str$)
-	str=str.Replace( "\","\\" )
-	str=str.Replace( "~q","\~q" )
-	str=str.Replace( "~n","\n" )
-	str=str.Replace( "~r","\r" )
-	str=str.Replace( "~t","\t" )
-	Return str
-End Function
-
-Function BmxEnquote$( str$ )
-	str=str.Replace( "~~","~~~~" )
-	str=str.Replace( "~q","~~q" )
-	str=str.Replace( "~n","~~n" )
-	str=str.Replace( "~r","~~r" )
-	str=str.Replace( "~t","~~t" )
-	str=str.Replace( "~0","~~0" )
-	str="~q"+str+"~q"
-	Return str
-End Function
-
-Function BmxUnquote$( str$, unicodeConvert:Int = False )
-	If str.length = 1 Or str[str.length - 1] <> Asc("~q") Then
-		Err "Expecting expression but encountered malformed string literal"
-	End If
-	str=str[1..str.Length-1]
-	If unicodeConvert Then
-		Local pos:Int = str.Find("~~")
-		While pos <> -1
-			If pos + 1 < str.length Then
-				If str[pos + 1] >= Asc("1") And str[pos + 1] <= Asc("9") Then
-					Local p2:Int = str.Find("~~", pos + 1)
-					If p2 <> -1 Then
-						Local s:String = Chr(str[pos + 1.. p2].ToInt())
-						str = str[..pos] + s + str[p2 + 1..]
-					End If
-				End If
-			End If
-		
-			pos = str.Find("~~", pos + 1)
-		Wend
-	End If
-	str=str.Replace( "~~~~","~~z" )	'a bit dodgy - uses bad esc sequence ~z 
-	str=str.Replace( "~~q","~q" )
-	str=str.Replace( "~~n","~n" )
-	str=str.Replace( "~~r","~r" )
-	str=str.Replace( "~~t","~t" )
-	str=str.Replace( "~~0","~0" )
-	str=str.Replace( "~~z","~~" )
-	Return str
-End Function
-
-Type TStack Extends TList
-
-	Method Push(obj:Object)
-		AddFirst(obj)
-	End Method
-
-	Method Length:Int()
-		Return count()
-	End Method
-	
-	Method Get:Object(index:Int)
-		Return ValueAtIndex(index)
-	End Method
-	
-	Method Pop:Object()
-		Return RemoveFirst()
-	End Method
-	
-End Type
-
-Type TStringList Extends TList
-	Method Join:String(s:String)
-		Local arr:String[] = New String[count()]
-		Local index:Int
-		For Local t:String = EachIn Self
-			arr[index] = t
-			index :+ 1
-		Next
-		
-		Return s.Join(arr)
-	End Method
-End Type
-
-Type TKeyValue
-	Field key:Object
-	Field value:Object
-	
-	Method Create:TKeyValue(key:Object,value:Object)
-		Self.key = key
-		Self.value = value
-		Return Self
-	End Method
-	
-	Method Compare:Int(other:Object)
-		If Not TKeyValue(other) Return 0
-		Return key.Compare(TKeyValue(other).key)
-	End Method
-	
-End Type
-
-Type TUnorderedMap
-
-	Field list:TList = New TList
-	Field map:TMap = New TMap
-	
-	Field valuesList:TList = New TList
-
-	Method Insert( key:Object,value:Object )
-		list.AddLAst(New TKeyValue.Create(key, value))
-		valuesList.AddLast(value)
-		map.Insert(key, value)
-	End Method
-	
-	Method Keys:TList()
-		Local klist:TList = New TList
-		For Local kv:TKeyValue = EachIn list
-			klist.AddLast(kv.key)
-		Next
-		Return klist
-	End Method
-	
-	Method Values:TList()
-		'Local vlist:TList = New TList
-		'For Local kv:TKeyValue = EachIn list
-		'	vlist.AddLast(kv.value)
-		'Next
-		Return valuesList
-	End Method
-	
-	Method Contains:Int( key:Object )
-		Return map.Contains(key)
-	End Method
-	
-	Method ValueForKey:Object( key:Object )
-		Return map.ValueForKey(key)
-	End Method
-End Type
-
-Function MakeKeywords:String()
-	Local keywords:String
-	
-	keywords :+ "import brl.classes~n"
-	keywords :+ "Asc%(v$)=~qbrl_blitz_keywords_asc~q~n"
-	keywords :+ "Sgn#(v#)=~qbrl_blitz_keywords_sgn~q~n"
-	keywords :+ "Chr$(v%)=~qbrl_blitz_keywords_chr~q~n"
-	keywords :+ "Len%(v:Object)=~qbrl_blitz_keywords_len~q~n"
-	keywords :+ "Min%(v1%,v2%)=~qbrl_blitz_keywords_min~q~n"
-	keywords :+ "Max%(v1%,v2%)=~qbrl_blitz_keywords_max~q~n"
-	'keywords :+ "SizeOf%(v%)=~qbrl_blitz_keywords_sizeof~q~n"
-	'keywords :+ "Incbin(v$)=~qbrl_blitz_keywords_incbin~q~n"
-	keywords :+ "IncbinPtr@*(v$)=~qbbIncbinPtr~q~n"
-	keywords :+ "IncbinLen%(v$)=~qbbIncbinLen~q~n"
- 
-	Return keywords
-End Function
-
-Function FilePath:String(path:String)
-	Local baseDir:String = ExtractDir(path)
-	Local bmxDir:String = baseDir + "/.bmx"
-	
-	If FileType(bmxDir) <> FILETYPE_DIR Then
-		Throw "Missing : " + bmxDir
-	End If
-	
-	Return bmxDir
-End Function
-
-Function BuildHeaderName:String(path:String)
-	If opt_buildtype = BUILDTYPE_MODULE Then
-		path = opt_modulename + "_" + StripDir(path)
-	Else
-		Local dir:String = ExtractDir(path).ToLower().Replace("/.bmx","")
-		dir = dir[dir.findLast("/") + 1..]
-		If dir.EndsWith(".mod") Then
-			dir = dir.Replace(".mod", "")
-		End If
-		Local file:String = StripDir(path).ToLower()
-		path = dir + "_" + file
-	End If
-	
-	Return TStringHelper.Sanitize(path, , True)
-End Function
-
-Rem
-bbdoc: Get the header file name from a given module ident, optionally with include path.
-End Rem
-Function ModuleHeaderFromIdent:String(ident:String, includePath:Int = False)
-	Local ns:String = ident[..ident.find(".")]
-	Local name:String = ident[ident.find(".") + 1..]
-	
-	Local file:String = name + ".bmx" + FileMung() + ".h"
-	
-	If includePath Then
-		file = ns + ".mod/" + name + ".mod/.bmx/" + file
-	End If
-	
-	Return file
-End Function
-
-Function HeaderFile:String(path:String, mung:String)
-	Local fileDir:String = FilePath(path)
-	Local file:String = StripDir(path)
-	
-	Return fileDir + "/" + file + mung + ".h"
-End Function
-
-Function OutputFilePath:String(path:String, mung:String, suffix:String, bmxDir:Int = False)
-	Local fileDir:String = FilePath(path)
-	If bmxDir Then
-		fileDir :+ "/.bmx"
-	End If
-	Local file:String = StripDir(path)
-	
-	Return fileDir + "/" + file + mung + "." + suffix
-End Function
-
-Function FileMung:String(makeApp:Int = False)
-	Local m:String = "."
-	
-	If makeApp Then
-		Select opt_apptype
-			Case APPTYPE_CONSOLE
-				m :+ "console."
-			Case APPTYPE_GUI
-				m :+ "gui."
-		End Select
-	End If
-	
-	If opt_release Then
-		m :+ "release"
-	Else
-		m :+ "debug"
-	End If
-	
-'	If opt_threaded Then
-'		m :+ ".mt"
-'	End If
-	
-	m :+ "." + opt_platform
-	
-	m :+ "." + opt_arch
-	
-	Return m
-End Function
-
-Function HeaderComment:String()
-	' TODO
-End Function
-
-
-Type TTemplateRecord
-
-	Field start:Int
-	Field file:String
-	Field source:String
-	
-	Method Create:TTemplateRecord(start:Int, file:String, source:String)
-		Self.start = start
-		Self.file = file
-		Self.source = source
-		Return Self
-	End Method
-	
-	Method ToString:String()
-
-		Local s:Byte Ptr = source.ToUTF8String()
-		Local slen:Int = strlen_(s)
-
-?Not bmxng		
-		Local dlen:Int = slen + 12
-?bmxng And (win32 Or ptr32)
-		Local dlen:UInt = slen + 12
-?bmxng And ptr64 And Not win32
-		Local dlen:ULong = slen + 12
-?
-		Local data:Byte[dlen]
-		
-		compress2(data, dlen, s, slen, 9)
-		
-		MemFree(s)
-		
-		Local t:String = "{" + start +","+ slen +","+ LangEnquote(file) + ","
-		
-		t :+ LangEnquote(TBase64.Encode(data, dlen, 0, TBase64.DONT_BREAK_LINES))
-
-		Return t + "}"
-
-	End Method
-	
-	Function Load:TTemplateRecord(start:Int, file:String, size:Int, source:String)
-		
-?Not bmxng		
-		Local dlen:Int = size + 1
-?bmxng And (win32 Or ptr32)
-		Local dlen:UInt = size + 1
-?bmxng And ptr64 And Not win32
-		Local dlen:ULong = size + 1
-?
-		Local data:Byte[dlen]
-		
-		Local s:Byte[] = TBase64.Decode(source)
-		
-		uncompress(data, dlen, s, s.length)
-	
-		Return New TTemplateRecord.Create(start, file, String.FromUTF8String(data))
-	End Function
-End Type
-
-Extern
-	Function strlen_:Int(s:Byte Ptr)="strlen"
-End Extern
+' 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.
+'
+SuperStrict
+
+Import BRL.LinkedList
+Import BRL.Map
+Import BRL.FileSystem
+Import Pub.zlib
+
+Import "options.bmx"
+Import "base.stringhelper.bmx"
+Import "base64.bmx"
+
+' debugging help
+Const DEBUG:Int = False
+Const ABORT_ON_NULL:Int = True
+Const PROFILER:Int = False
+Const DEBUGSTOP_ON_ERROR:Int = False
+
+Global ENV_LANG$
+
+Global _errInfo$
+Global _errStack:TList = New TList
+
+' bytes offset to the first field
+Global OBJECT_BASE_OFFSET:Int = 8
+' 4 bytes on 32-bit, 8 bytes on 64-bit
+Global POINTER_SIZE:Int = 4
+
+Global _symbols$[]=[ "..","[]",":*",":/",":+",":-",":|",":&",":~~",":shr",":shl",":sar",":mod"]
+Global _symbols_map$[]=[ "..","[]","*=","/=","+=","-=","|=","&=","^=",">>=", "<<=",">>=","%=" ]
+
+Function PushErr( errInfo$ )
+	_errStack.AddLast _errInfo
+	_errInfo=errInfo
+End Function
+
+Function PopErr()
+	_errInfo=String(_errStack.RemoveLast())
+End Function
+
+Function Err( err$ )
+	If DEBUGSTOP_ON_ERROR Then
+		DebugStop ' useful for debugging!
+	End If
+	Throw "Compile Error: "+err + "~n" + _errInfo + "~n"
+End Function
+
+Function Warn( err$ )
+	'If DEBUGSTOP_ON_ERROR Then
+	'	DebugStop ' useful for debugging!
+	'End If
+	Print "Compile Warning: "+err + "~n" + _errInfo + "~n"
+End Function
+
+Function FormatError:String(path:String, line:Int, char:Int)
+	Return "[" + path + ";" + line + ";" + char + "]"
+End Function
+
+Function InternalErr()
+	If DEBUGSTOP_ON_ERROR Then
+		DebugStop ' useful for debugging!
+	End If
+	Throw "Internal Error.~n" + _errInfo + "~n"
+End Function
+
+Function IsSpace:Int( ch:Int )
+	Return ch<=Asc(" ") Or ch=$A0 ' NO-BREAK SPACE (U+00A0)
+End Function
+
+Function IsDigit:Int( ch:Int )
+	Return ch>=Asc("0") And ch<=Asc("9")
+End Function
+
+Function IsAlpha:Int( ch:Int )
+	Return (ch>=Asc("A") And ch<=Asc("Z")) Or (ch>=Asc("a") And ch<=Asc("z"))
+End Function
+
+Function IsBinDigit:Int( ch:Int )
+	Return ch=Asc("0") Or ch=Asc("1")
+End Function
+
+Function IsHexDigit:Int( ch:Int )
+	Return IsDigit(ch) Or (ch>=Asc("A") And ch<=Asc("F")) Or (ch>=Asc("a") And ch<=Asc("f"))
+End Function
+
+Function Todo() 
+	Err "TODO!"
+End Function
+
+Function IsStandardFunc:Int(func:String)
+	func = func.ToLower()
+	
+	Global funcs:String = ";isalnum;isalpha;isascii;isblank;iscntrl;isdigit;isgraph;islower;isprint;ispunct;isspace;isupper;isxdigit;" + ..
+		"strlen;_wgetenv;_wputenv;"
+	
+	Return funcs.Find(func) > 0
+End Function
+
+Function mapSymbol:String(sym:String)
+	For Local i:Int = 0 Until _symbols.length
+		If sym = _symbols[i] Then
+			Return _symbols_map[i]
+		End If
+	Next
+	Return sym
+End Function
+
+
+'enquote depending on ENV_LANG
+'
+Function LangEnquote$( str$ )
+	str=EscapeString(str)
+'	str=str.Replace( "~0","\0" )	'Fix me?
+	For Local i:Int=0 Until str.Length
+		If str[i]>=32 And str[i]<128 Continue
+		Local t$,n:Int=str[i]
+		While n
+			Local c:Int=(n&15)+48
+			If c>=58 c:+97-58
+			t=Chr( c )+t
+			n=(n Shr 4) & $0fffffff
+		Wend
+		If Not t t="0"
+		If ENV_LANG = "cpp" Then
+		'Case "cpp"
+			t="~q~q\x"+t+"~q~q"
+		Else
+			t="\u"+("0000"+t)[-4..]
+		End If
+		str=str[..i]+t+str[i+1..]
+		i:+t.Length-1
+	Next
+	str="~q"+str+"~q"
+	If ENV_LANG="cpp" str="L"+str
+	Return str
+End Function
+
+Function EscapeString$(str$)
+	str=str.Replace( "\","\\" )
+	str=str.Replace( "~q","\~q" )
+	str=str.Replace( "~n","\n" )
+	str=str.Replace( "~r","\r" )
+	str=str.Replace( "~t","\t" )
+	Return str
+End Function
+
+Function BmxEnquote$( str$ )
+	str=str.Replace( "~~","~~~~" )
+	str=str.Replace( "~q","~~q" )
+	str=str.Replace( "~n","~~n" )
+	str=str.Replace( "~r","~~r" )
+	str=str.Replace( "~t","~~t" )
+	str=str.Replace( "~0","~~0" )
+	str="~q"+str+"~q"
+	Return str
+End Function
+
+Function BmxUnquote$( str$, unicodeConvert:Int = False )
+	If str.length = 1 Or str[str.length - 1] <> Asc("~q") Then
+		Err "Expecting expression but encountered malformed string literal"
+	End If
+	str=str[1..str.Length-1]
+	If unicodeConvert Then
+		Local pos:Int = str.Find("~~")
+		While pos <> -1
+			If pos + 1 < str.length Then
+				If str[pos + 1] >= Asc("1") And str[pos + 1] <= Asc("9") Then
+					Local p2:Int = str.Find("~~", pos + 1)
+					If p2 <> -1 Then
+						Local s:String = Chr(str[pos + 1.. p2].ToInt())
+						str = str[..pos] + s + str[p2 + 1..]
+					End If
+				End If
+			End If
+		
+			pos = str.Find("~~", pos + 1)
+		Wend
+	End If
+	str=str.Replace( "~~~~","~~z" )	'a bit dodgy - uses bad esc sequence ~z 
+	str=str.Replace( "~~q","~q" )
+	str=str.Replace( "~~n","~n" )
+	str=str.Replace( "~~r","~r" )
+	str=str.Replace( "~~t","~t" )
+	str=str.Replace( "~~0","~0" )
+	str=str.Replace( "~~z","~~" )
+	Return str
+End Function
+
+Type TStack Extends TList
+
+	Method Push(obj:Object)
+		AddFirst(obj)
+	End Method
+
+	Method Length:Int()
+		Return count()
+	End Method
+	
+	Method Get:Object(index:Int)
+		Return ValueAtIndex(index)
+	End Method
+	
+	Method Pop:Object()
+		Return RemoveFirst()
+	End Method
+	
+End Type
+
+Type TStringList Extends TList
+	Method Join:String(s:String)
+		Local arr:String[] = New String[count()]
+		Local index:Int
+		For Local t:String = EachIn Self
+			arr[index] = t
+			index :+ 1
+		Next
+		
+		Return s.Join(arr)
+	End Method
+End Type
+
+Type TKeyValue
+	Field key:Object
+	Field value:Object
+	
+	Method Create:TKeyValue(key:Object,value:Object)
+		Self.key = key
+		Self.value = value
+		Return Self
+	End Method
+	
+	Method Compare:Int(other:Object)
+		If Not TKeyValue(other) Return 0
+		Return key.Compare(TKeyValue(other).key)
+	End Method
+	
+End Type
+
+Type TUnorderedMap
+
+	Field list:TList = New TList
+	Field map:TMap = New TMap
+	
+	Field valuesList:TList = New TList
+
+	Method Insert( key:Object,value:Object )
+		list.AddLAst(New TKeyValue.Create(key, value))
+		valuesList.AddLast(value)
+		map.Insert(key, value)
+	End Method
+	
+	Method Keys:TList()
+		Local klist:TList = New TList
+		For Local kv:TKeyValue = EachIn list
+			klist.AddLast(kv.key)
+		Next
+		Return klist
+	End Method
+	
+	Method Values:TList()
+		'Local vlist:TList = New TList
+		'For Local kv:TKeyValue = EachIn list
+		'	vlist.AddLast(kv.value)
+		'Next
+		Return valuesList
+	End Method
+	
+	Method Contains:Int( key:Object )
+		Return map.Contains(key)
+	End Method
+	
+	Method ValueForKey:Object( key:Object )
+		Return map.ValueForKey(key)
+	End Method
+End Type
+
+Function MakeKeywords:String()
+	Local keywords:String
+	
+	keywords :+ "import brl.classes~n"
+	keywords :+ "Asc%(v$)=~qbrl_blitz_keywords_asc~q~n"
+	keywords :+ "Sgn#(v#)=~qbrl_blitz_keywords_sgn~q~n"
+	keywords :+ "Chr$(v%)=~qbrl_blitz_keywords_chr~q~n"
+	keywords :+ "Len%(v:Object)=~qbrl_blitz_keywords_len~q~n"
+	keywords :+ "Min%(v1%,v2%)=~qbrl_blitz_keywords_min~q~n"
+	keywords :+ "Max%(v1%,v2%)=~qbrl_blitz_keywords_max~q~n"
+	'keywords :+ "SizeOf%(v%)=~qbrl_blitz_keywords_sizeof~q~n"
+	'keywords :+ "Incbin(v$)=~qbrl_blitz_keywords_incbin~q~n"
+	keywords :+ "IncbinPtr@*(v$)=~qbbIncbinPtr~q~n"
+	keywords :+ "IncbinLen%(v$)=~qbbIncbinLen~q~n"
+ 
+	Return keywords
+End Function
+
+Function FilePath:String(path:String)
+	Local baseDir:String = ExtractDir(path)
+	Local bmxDir:String = baseDir + "/.bmx"
+	
+	If FileType(bmxDir) <> FILETYPE_DIR Then
+		Throw "Missing : " + bmxDir
+	End If
+	
+	Return bmxDir
+End Function
+
+Function BuildHeaderName:String(path:String)
+	If opt_buildtype = BUILDTYPE_MODULE Then
+		path = opt_modulename + "_" + StripDir(path)
+	Else
+		Local dir:String = ExtractDir(path).ToLower().Replace("/.bmx","")
+		dir = dir[dir.findLast("/") + 1..]
+		If dir.EndsWith(".mod") Then
+			dir = dir.Replace(".mod", "")
+		End If
+		Local file:String = StripDir(path).ToLower()
+		path = dir + "_" + file
+	End If
+	
+	Return TStringHelper.Sanitize(path, , True)
+End Function
+
+Rem
+bbdoc: Get the header file name from a given module ident, optionally with include path.
+End Rem
+Function ModuleHeaderFromIdent:String(ident:String, includePath:Int = False)
+	Local ns:String = ident[..ident.find(".")]
+	Local name:String = ident[ident.find(".") + 1..]
+	
+	Local file:String = name + ".bmx" + FileMung() + ".h"
+	
+	If includePath Then
+		file = ns + ".mod/" + name + ".mod/.bmx/" + file
+	End If
+	
+	Return file
+End Function
+
+Function HeaderFile:String(path:String, mung:String)
+	Local fileDir:String = FilePath(path)
+	Local file:String = StripDir(path)
+	
+	Return fileDir + "/" + file + mung + ".h"
+End Function
+
+Function OutputFilePath:String(path:String, mung:String, suffix:String, bmxDir:Int = False)
+	Local fileDir:String = FilePath(path)
+	If bmxDir Then
+		fileDir :+ "/.bmx"
+	End If
+	Local file:String = StripDir(path)
+	
+	Return fileDir + "/" + file + mung + "." + suffix
+End Function
+
+Function FileMung:String(makeApp:Int = False)
+	Local m:String = "."
+	
+	If makeApp Then
+		Select opt_apptype
+			Case APPTYPE_CONSOLE
+				m :+ "console."
+			Case APPTYPE_GUI
+				m :+ "gui."
+		End Select
+	End If
+	
+	If opt_release Then
+		m :+ "release"
+	Else
+		m :+ "debug"
+	End If
+	
+'	If opt_threaded Then
+'		m :+ ".mt"
+'	End If
+	
+	m :+ "." + opt_platform
+	
+	m :+ "." + opt_arch
+	
+	Return m
+End Function
+
+Function HeaderComment:String()
+	' TODO
+End Function
+
+
+Type TTemplateRecord
+
+	Field start:Int
+	Field file:String
+	Field source:String
+	
+	Method Create:TTemplateRecord(start:Int, file:String, source:String)
+		Self.start = start
+		Self.file = file
+		Self.source = source
+		Return Self
+	End Method
+	
+	Method ToString:String()
+
+		Local s:Byte Ptr = source.ToUTF8String()
+?Not bmxng
+		Local slen:Int = strlen_(s)
+?bmxng
+		Local slen:UInt = strlen_(s)
+?
+
+?Not bmxng		
+		Local dlen:Int = slen + 12
+?bmxng And (win32 Or ptr32)
+		Local dlen:UInt = slen + 12
+?bmxng And ptr64 And Not win32
+		Local dlen:ULong = slen + 12
+?
+		Local data:Byte[dlen]
+		
+		compress2(data, dlen, s, slen, 9)
+		
+		MemFree(s)
+		
+		Local t:String = "{" + start +","+ slen +","+ LangEnquote(file) + ","
+		
+		t :+ LangEnquote(TBase64.Encode(data, Int(dlen), 0, TBase64.DONT_BREAK_LINES))
+
+		Return t + "}"
+
+	End Method
+	
+	Function Load:TTemplateRecord(start:Int, file:String, size:Int, source:String)
+		
+?Not bmxng		
+		Local dlen:Int = size + 1
+?bmxng And (win32 Or ptr32)
+		Local dlen:UInt = size + 1
+?bmxng And ptr64 And Not win32
+		Local dlen:ULong = size + 1
+?
+		Local data:Byte[dlen]
+		
+		Local s:Byte[] = TBase64.Decode(source)
+?Not bmxng
+		uncompress(data, dlen, s, s.length)
+?bmxng
+		uncompress(data, dlen, s, UInt(s.length))
+?	
+		Return New TTemplateRecord.Create(start, file, String.FromUTF8String(data))
+	End Function
+End Type
+
+Type TCallback
+	Method Callback(obj:Object) Abstract
+End Type
+
+Extern
+	Function strlen_:Int(s:Byte Ptr)="strlen"
+End Extern

+ 39 - 15
ctranslator.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 '
 '
@@ -705,6 +705,11 @@ t:+"NULLNULLNULL"
 				initTrans = "=" + cast + init.Trans()
 				initTrans = "=" + cast + init.Trans()
 			End If
 			End If
 		End If
 		End If
+		
+		Local volTrans:String = " "
+		If decl.volatile Then
+			volTrans = " volatile "
+		End If
 	
 	
 		If Not declare And opt_debug Then
 		If Not declare And opt_debug Then
 			Local ty:TType = decl.ty
 			Local ty:TType = decl.ty
@@ -738,21 +743,21 @@ t:+"NULLNULLNULL"
 						If TObjectType(ty).classdecl.IsInterface() Then
 						If TObjectType(ty).classdecl.IsInterface() Then
 							Return TransType( ty, decl.munged )+" "+decl.munged + initTrans
 							Return TransType( ty, decl.munged )+" "+decl.munged + initTrans
 						Else
 						Else
-							Return TransType( ty, decl.munged )+" "+decl.munged + initTrans
+							Return TransType( ty, decl.munged )+ volTrans +decl.munged + initTrans
 						End If
 						End If
 					Else
 					Else
 						If TObjectType(ty).classdecl.IsStruct() Then
 						If TObjectType(ty).classdecl.IsStruct() Then
 							Return TransType( ty, decl.munged )+" "+decl.munged + initTrans
 							Return TransType( ty, decl.munged )+" "+decl.munged + initTrans
 						Else
 						Else
-							If decl.volatile Then
-								Return TransType( ty, decl.munged )+" volatile "+decl.munged + initTrans
-							Else
-								Return TransType( ty, decl.munged )+" "+decl.munged + initTrans
-							End If
+							'If decl.volatile Then
+								Return TransType( ty, decl.munged )+ volTrans +decl.munged + initTrans
+							'Else
+							'	Return TransType( ty, decl.munged )+" "+decl.munged + initTrans
+							'End If
 						End If
 						End If
 					End If
 					End If
 				Else
 				Else
-					Return TransType( ty, decl.munged )+" "+decl.munged + initTrans
+					Return TransType( ty, decl.munged )+ volTrans +decl.munged + initTrans
 				End If
 				End If
 			End If
 			End If
 		End If
 		End If
@@ -783,7 +788,11 @@ t:+"NULLNULLNULL"
 					End If
 					End If
 				End If
 				End If
 			Else
 			Else
-				Return TransType( decl.ty, decl.munged )+" "+decl.munged + "=" + TransValue(decl.ty, "")
+				If TLocalDecl(decl) And TLocalDecl(decl).volatile Then
+					Return TransType( decl.ty, decl.munged )+" volatile "+decl.munged + "=" + TransValue(decl.ty, "")
+				Else
+					Return TransType( decl.ty, decl.munged )+" "+decl.munged + "=" + TransValue(decl.ty, "")
+				End If
 			End If
 			End If
 		End If
 		End If
 	End Method
 	End Method
@@ -1018,8 +1027,15 @@ t:+"NULLNULLNULL"
 										Return "_" + decl.munged+TransArgs( args,decl, TransSubExpr( lhs ) )
 										Return "_" + decl.munged+TransArgs( args,decl, TransSubExpr( lhs ) )
 									End If
 									End If
 								Else
 								Else
-									Local class:String = Bra(TransSubExpr( lhs )) + "->clas" + tSuper
-									Return class + "->" + TransFuncPrefix(cdecl, decl) + FuncDeclMangleIdent(decl)+TransArgs( args,decl, TransSubExpr( lhs ) )
+									Local obj:String = TransSubExpr( lhs )
+									Local preObj:String = obj
+									
+									If opt_debug Then
+										preObj = TransDebugNullObjectError(obj, cdecl)
+									End If
+									
+									Local class:String = Bra(preObj) + "->clas" + tSuper
+									Return class + "->" + TransFuncPrefix(cdecl, decl) + FuncDeclMangleIdent(decl)+TransArgs( args,decl, obj )
 '									Local class:String = Bra(lvarInit) + "->clas" + tSuper
 '									Local class:String = Bra(lvarInit) + "->clas" + tSuper
 '									Return class + "->" + TransFuncPrefix(cdecl, decl) + FuncDeclMangleIdent(decl)+TransArgs( args,decl, lvar )
 '									Return class + "->" + TransFuncPrefix(cdecl, decl) + FuncDeclMangleIdent(decl)+TransArgs( args,decl, lvar )
 								End If
 								End If
@@ -1589,7 +1605,11 @@ t:+"NULLNULLNULL"
 			End If
 			End If
 
 
 			If expr.instanceExpr Then
 			If expr.instanceExpr Then
-				t = "_" + ctorMunged + "_ObjectNew" + TransArgs( expr.args,expr.ctor, Bra(expr.instanceExpr.Trans()) + "->clas" )
+				If expr.classDEcl.IsStruct() Then
+					t = ctorMunged + "_ObjectNew" + TransArgs( expr.args,expr.ctor)
+				Else
+					t = "_" + ctorMunged + "_ObjectNew" + TransArgs( expr.args,expr.ctor, Bra(expr.instanceExpr.Trans()) + "->clas" )
+				End If
 			Else
 			Else
 				If ClassHasObjectField(expr.classDecl) And Not expr.classDecl.IsStruct() Then
 				If ClassHasObjectField(expr.classDecl) And Not expr.classDecl.IsStruct() Then
 					t = "_" + ctorMunged + "_ObjectNew" + TransArgs( expr.args,expr.ctor, "&" + expr.classDecl.actual.munged )
 					t = "_" + ctorMunged + "_ObjectNew" + TransArgs( expr.args,expr.ctor, "&" + expr.classDecl.actual.munged )
@@ -4391,6 +4411,10 @@ End Rem
 			' field initialisation
 			' field initialisation
 			For Local decl:TFieldDecl=EachIn classDecl.Decls()
 			For Local decl:TFieldDecl=EachIn classDecl.Decls()
 			
 			
+				If Not decl.IsSemanted() Then
+					decl.Semant()
+				End If
+			
 				Local fld:String
 				Local fld:String
 	
 	
 				' ((int*)((char*)o + 5))[0] =
 				' ((int*)((char*)o + 5))[0] =
@@ -4749,11 +4773,11 @@ End Rem
 
 
 	Method TransFieldRef:String(decl:TFieldDecl, variable:String, exprType:TType = Null)
 	Method TransFieldRef:String(decl:TFieldDecl, variable:String, exprType:TType = Null)
 		Local s:String = variable
 		Local s:String = variable
-'DebugStop
+		
 		Local ind:String = "->"
 		Local ind:String = "->"
 		If decl.scope And TClassDecl(decl.scope) And TClassDecl(decl.scope).IsStruct() Then
 		If decl.scope And TClassDecl(decl.scope) And TClassDecl(decl.scope).IsStruct() Then
-			Local exprIsStruct:Int = TObjectType(exprType) And TObjectType(exprType).classDecl.attrs & CLASS_STRUCT
-			If exprType And (exprIsStruct Or Not IsPointerType(exprType)) And variable <> "o" Then
+			Local exprIsStruct:Int = Not exprType Or (TObjectType(exprType) And TObjectType(exprType).classDecl.attrs & CLASS_STRUCT)
+			If (exprIsStruct Or (exprType And Not IsPointerType(exprType))) And variable <> "o" Then
 				ind = "."
 				ind = "."
 			End If
 			End If
 		End If
 		End If

+ 191 - 87
decl.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 '
 '
@@ -42,6 +42,7 @@ Const DECL_PROTECTED:Int=    $4000000
 Const DECL_API_CDECL:Int=   $00000000
 Const DECL_API_CDECL:Int=   $00000000
 Const DECL_API_STDCALL:Int= $10000000
 Const DECL_API_STDCALL:Int= $10000000
 Const DECL_API_DEFAULT:Int=DECL_API_CDECL
 Const DECL_API_DEFAULT:Int=DECL_API_CDECL
+Const DECL_API_FLAGS:Int=   DECL_API_CDECL | DECL_API_STDCALL
 
 
 Const DECL_NESTED:Int=      $20000000
 Const DECL_NESTED:Int=      $20000000
 
 
@@ -399,7 +400,7 @@ Type TValDecl Extends TDecl
 					End If
 					End If
 				End If
 				End If
 			End If
 			End If
-			
+
 			ty=declTy.Semant()
 			ty=declTy.Semant()
 
 
 			If Not deferInit Then
 			If Not deferInit Then
@@ -555,7 +556,11 @@ Type TConstDecl Extends TValDecl
 	End Method
 	End Method
 
 
 	Method OnCopy:TDecl(deep:Int = True)
 	Method OnCopy:TDecl(deep:Int = True)
-		Return New TConstDecl.Create( ident,ty,CopyInit(), attrs )
+		If IsSemanted() Then
+			Return New TConstDecl.Create( ident,ty,CopyInit(), attrs )
+		Else
+			Return New TConstDecl.Create( ident, declTy, declInit, attrs)
+		End If
 	End Method
 	End Method
 	
 	
 	Method OnSemant()
 	Method OnSemant()
@@ -582,9 +587,10 @@ End Type
 Type TLocalDecl Extends TVarDecl
 Type TLocalDecl Extends TVarDecl
 
 
 	Field done:Int
 	Field done:Int
-	Field volatile:Int = True
+	Field volatile:Int = False
+	Field declaredInTry:Int
 
 
-	Method Create:TLocalDecl( ident$,ty:TType,init:TExpr,attrs:Int=0, generated:Int = False, volatile:Int = True )
+	Method Create:TLocalDecl( ident$,ty:TType,init:TExpr,attrs:Int=0, generated:Int = False, volatile:Int = False )
 		Self.ident=ident
 		Self.ident=ident
 		Self.declTy=ty
 		Self.declTy=ty
 		Self.declInit=init
 		Self.declInit=init
@@ -599,13 +605,23 @@ Type TLocalDecl Extends TVarDecl
 		decl.scope = scope
 		decl.scope = scope
 		decl.ty = ty
 		decl.ty = ty
 		decl.init = init
 		decl.init = init
+		decl.declaredInTry = declaredInTry
 		Return decl
 		Return decl
 	End Method
 	End Method
 
 
 	Method GetDeclPrefix:String()
 	Method GetDeclPrefix:String()
 		Return "Local "
 		Return "Local "
 	End Method
 	End Method
-	
+
+	Method OnSemant()
+		If declTy Then
+			If TObjectType(declTy) Or TArrayType(declTy) Then
+				volatile = True
+			End If
+		End If
+		Super.OnSemant()
+	End Method
+		
 	Method ToString$()
 	Method ToString$()
 		Return GetDeclPrefix() + Super.ToString()
 		Return GetDeclPrefix() + Super.ToString()
 	End Method
 	End Method
@@ -970,8 +986,11 @@ Type TScopeDecl Extends TDecl
 				End If
 				End If
 				
 				
 				Local found:Int
 				Local found:Int
+				' remove matching functions from decl list.
+				' a match should match exactly. If an arg is a subclass of another
+				' then that is not a match, and we will distance test later..
 				For Local func:TFuncDecl = EachIn declList
 				For Local func:TFuncDecl = EachIn declList
-					If func.equalsFunc(fdecl) Then
+					If func.equalsFunc(fdecl, True) Then
 						found = True
 						found = True
 						Exit
 						Exit
 'Else
 'Else
@@ -1123,7 +1142,7 @@ Type TScopeDecl Extends TDecl
 		Return decl
 		Return decl
 	End Method
 	End Method
 
 
-	Method FindType:TType( ident$,args:TType[] )
+	Method FindType:TType( ident$,args:TType[], callback:TCallback = Null )
 'DebugLog Self.ident + "::FindType::" + ident
 'DebugLog Self.ident + "::FindType::" + ident
 		Local decl:Object=(GetDecl( ident ))
 		Local decl:Object=(GetDecl( ident ))
 		If decl Then
 		If decl Then
@@ -1139,13 +1158,13 @@ Type TScopeDecl Extends TDecl
 			If cdecl
 			If cdecl
 				cdecl.AssertAccess
 				cdecl.AssertAccess
 				If Not cdecl.instanceof Then
 				If Not cdecl.instanceof Then
-					cdecl=cdecl.GenClassInstance( args )
+					cdecl=cdecl.GenClassInstance( args, False, callback, Null )
 					cdecl.Semant
 					cdecl.Semant
 				End If
 				End If
 				Return cdecl.objectType
 				Return cdecl.objectType
 			EndIf
 			EndIf
 		EndIf
 		EndIf
-		If scope Return scope.FindType( ident,args )
+		If scope Return scope.FindType( ident,args, callback )
 	End Method
 	End Method
 	
 	
 	Method FindScopeDecl:TScopeDecl( ident$ )
 	Method FindScopeDecl:TScopeDecl( ident$ )
@@ -1592,7 +1611,20 @@ End Rem
 		
 		
 		If scope Return scope.FindLoop( ident )
 		If scope Return scope.FindLoop( ident )
 	End Method
 	End Method
-	
+
+	Method FindTry:TTryStmtDecl()
+
+		If TTryStmtDecl(Self) Then
+			Return TTryStmtDecl(Self)
+		End If
+
+		If TFuncDecl(scope) Or TModuleDecl(scope)
+			Return Null
+		End If
+		
+		If scope Return scope.FindTry()
+	End Method
+
 	Method OnSemant()
 	Method OnSemant()
 	End Method
 	End Method
 	
 	
@@ -1855,12 +1887,17 @@ Type TFuncDecl Extends TBlockDecl
 		Return (attrs & FUNC_FIELD)<>0
 		Return (attrs & FUNC_FIELD)<>0
 	End Method
 	End Method
 		
 		
-	Method EqualsArgs:Int( decl:TFuncDecl ) ' careful, this is not commutative!
+	' exactMatch requires args to be equal. If an arg is a subclass, that is not a match.
+	Method EqualsArgs:Int( decl:TFuncDecl, exactMatch:Int = False ) ' careful, this is not commutative!
 		If argDecls.Length<>decl.argDecls.Length Return False
 		If argDecls.Length<>decl.argDecls.Length Return False
 		For Local i:Int=0 Until argDecls.Length
 		For Local i:Int=0 Until argDecls.Length
+			' ensure arg decls have been semanted
+			decl.argDecls[i].Semant()
+			argDecls[i].Semant()
+			
 			' objects can be subclasses as well as the same.
 			' objects can be subclasses as well as the same.
 			If TObjectType(decl.argDecls[i].ty) Then
 			If TObjectType(decl.argDecls[i].ty) Then
-				If Not decl.argDecls[i].ty.EqualsType( argDecls[i].ty ) And Not decl.argDecls[i].ty.ExtendsType( argDecls[i].ty ) Return False
+				If Not decl.argDecls[i].ty.EqualsType( argDecls[i].ty ) And (exactMatch Or Not decl.argDecls[i].ty.ExtendsType( argDecls[i].ty )) Return False
 			Else
 			Else
 				If Not decl.argDecls[i].ty.EqualsType( argDecls[i].ty ) Return False
 				If Not decl.argDecls[i].ty.EqualsType( argDecls[i].ty ) Return False
 			End If
 			End If
@@ -1868,12 +1905,13 @@ Type TFuncDecl Extends TBlockDecl
 		Return True
 		Return True
 	End Method
 	End Method
 
 
-	Method EqualsFunc:Int( decl:TFuncDecl ) ' careful, this is not commutative!
+	' exactMatch requires args to be equal. If an arg is a subclass, that is not a match.
+	Method EqualsFunc:Int( decl:TFuncDecl, exactMatch:Int = False) ' careful, this is not commutative!
 		If IsCtor() Then
 		If IsCtor() Then
-			Return EqualsArgs( decl )
+			Return EqualsArgs( decl, exactMatch )
 		Else
 		Else
 			' matching args?
 			' matching args?
-			If EqualsArgs( decl ) Then
+			If EqualsArgs( decl, exactMatch ) Then
 				' matching return type?
 				' matching return type?
 				If TObjectType(retType) Or TArrayType(retType) Or TStringType(retType) Then
 				If TObjectType(retType) Or TArrayType(retType) Or TStringType(retType) Then
 					Return retType.EqualsType( decl.retType ) Or retType.ExtendsType( decl.retType )' Or decl.retType.EqualsType( retType )) And EqualsArgs( decl )
 					Return retType.EqualsType( decl.retType ) Or retType.ExtendsType( decl.retType )' Or decl.retType.EqualsType( retType )) And EqualsArgs( decl )
@@ -1923,7 +1961,6 @@ Type TFuncDecl Extends TBlockDecl
 					End If
 					End If
 				End If
 				End If
 			End If
 			End If
-		
 			retType=retTypeExpr.Semant()
 			retType=retTypeExpr.Semant()
 			
 			
 			' for Strict code, a void return type becomes Int
 			' for Strict code, a void return type becomes Int
@@ -1936,7 +1973,7 @@ Type TFuncDecl Extends TBlockDecl
 		If TArrayType( retType ) And Not retType.EqualsType( retType.ActualType() )
 		If TArrayType( retType ) And Not retType.EqualsType( retType.ActualType() )
 '			Err "Return type cannot be an array of generic objects."
 '			Err "Return type cannot be an array of generic objects."
 		EndIf
 		EndIf
-		
+
 		'semant args
 		'semant args
 		For Local arg:TArgDecl=EachIn argDecls
 		For Local arg:TArgDecl=EachIn argDecls
 			InsertDecl arg
 			InsertDecl arg
@@ -2176,6 +2213,16 @@ Type TNullDecl Extends TClassDecl
 
 
 End Type
 End Type
 
 
+' used to handle recursive generics
+' by setting the superclass as soon as we know it,
+' which allows the semanting of the instance to complete.
+Type TClassDeclCallback Extends TCallback
+	Field decl:TClassDecl
+	Method callback(obj:Object)
+		decl.superClass = TClassDecl(obj)
+	End Method
+End Type
+
 Type TClassDecl Extends TScopeDecl
 Type TClassDecl Extends TScopeDecl
 
 
 	Field lastOffset:Int
 	Field lastOffset:Int
@@ -2300,7 +2347,7 @@ Rem
 		Return inst
 		Return inst
 	End Method
 	End Method
 End Rem
 End Rem
-	Method GenClassInstance:TClassDecl( instArgs:TType[], declImported:Int = False )
+	Method GenClassInstance:TClassDecl( instArgs:TType[], declImported:Int = False, callback:TCallback = Null, templateDets:TTemplateDets = Null )
 
 
 		If instanceof InternalErr
 		If instanceof InternalErr
 		
 		
@@ -2312,9 +2359,34 @@ End Rem
 			Next
 			Next
 		EndIf
 		EndIf
 		
 		
+		Local originalInstArgs:TType[] = instArgs
+		
 		'check number of args
 		'check number of args
-		If args.Length<>instArgs.Length
-			Err "Wrong number of type arguments for class "+ToString()
+		If args.Length<>instArgs.Length Then
+			If Not templateDets Or args.Length > instArgs.Length Then
+				Err "Wrong number of type arguments for class "+ToString()
+			Else
+				' create new instArgs with matched aliases
+				Local newInstArgs:TType[] = New TType[args.length]
+				For Local i:Int = 0 Until args.length
+					Local arg:TTemplateArg = args[i]
+					Local instArg:TType
+					' find match
+					For Local n:Int = 0 Until templateDets.args.length
+						Local templateArg:TTemplateArg = templateDets.args[n]
+						If templateArg.ident.ToLower() = arg.ident.ToLower() Then
+							instArg = instArgs[n]
+							Exit
+						End If
+					Next
+					If Not instArg Then
+						Err "Cannot find argument type '" + arg.ident + "' for class " + ToString()
+					End If
+					newInstArgs[i] = instArg
+				Next
+				
+				instArgs = newInstArgs
+			End If
 		EndIf
 		EndIf
 		
 		
 		'look for existing instance
 		'look for existing instance
@@ -2328,8 +2400,19 @@ End Rem
 			Next
 			Next
 			If equal Return inst
 			If equal Return inst
 		Next
 		Next
+		
+		If Not templateDets Then
+			' pass in the original instargs, as an inner-inner type will be able to see all of the originals
+			templateDets = New TTemplateDets.Create(originalInstArgs, args)
+		End If
 
 
-		Local inst:TClassDecl=New TClassDecl.Create( ident,Null,superTy,impltys, attrs )
+		Local inst:TClassDecl = TClassDecl(TGenProcessor.processor.ParseGeneric(templateSource, templateDets))
+		inst.ident=ident
+		inst.args=Null
+		inst.instances = Null
+		inst.superTy=superTy
+		inst.impltys=impltys
+		inst.attrs=attrs
 
 
 		inst.attrs:&~DECL_SEMANTED
 		inst.attrs:&~DECL_SEMANTED
 
 
@@ -2343,26 +2426,52 @@ End Rem
 		
 		
 		inst.declImported = declImported
 		inst.declImported = declImported
 
 
+		If callback Then
+			callback.callback(inst)
+		End If
+
+		PushEnv inst
+		
+		' install aliases
+		For Local i:Int=0 Until args.Length
+			inst.InsertDecl New TAliasDecl.Create( args[i].ident,instArgs[i],0 )
+		Next
+
+		' process parameter types
 		For Local i:Int=0 Until args.Length
 		For Local i:Int=0 Until args.Length
 		
 		
+			Local arg:TTemplateArg = args[i]
+
 			' ensure parameter types are compatible
 			' ensure parameter types are compatible
-			If args[i].superTy Then
-				args[i].superTy = args[i].superTy.Semant()
-				If Not instArgs[i].EqualsType(args[i].superTy) And Not instArgs[i].ExtendsType(args[i].superTy) Then
-					Err "Type parameter '" + instArgs[i].ToString() + "' is not within its bound; should extend '" + args[i].superTy.ToString() + "'"
+			If arg.superTy Then
+
+				'If Not instArgs[i].IsSemanted() Then
+				If TObjectType(instArgs[i]) Then
+					TObjectType(instArgs[i]).classDecl.Semant()
 				End If
 				End If
+				'End If
+			
+				For Local n:Int = 0 Until arg.superTy.length
+
+					arg.superTy[n] = arg.superTy[n].Semant()
+
+					If Not instArgs[i].EqualsType(arg.superTy[n]) And Not instArgs[i].ExtendsType(arg.superTy[n]) Then
+						Err "Type parameter '" + instArgs[i].ToString() + "' is not within its bound; should extend '" + arg.superTy[n].ToString() + "'"
+					End If
+				Next
 			End If
 			End If
 		
 		
-			inst.InsertDecl New TAliasDecl.Create( args[i].ident,instArgs[i],0 )
 		Next
 		Next
+		
+		PopEnv
 
 
-		For Local decl:TDecl=EachIn _decls
-			If TClassDecl(decl) Then
-				inst.InsertDecl TClassDecl(decl).GenClassInstance(instArgs, declImported), True
-			Else
-				inst.InsertDecl decl.Copy(), True
-			End If
-		Next
+'		For Local decl:TDecl=EachIn _decls
+'			If TClassDecl(decl) Then
+'				inst.InsertDecl TClassDecl(decl).GenClassInstance(instArgs, declImported), True
+'			Else
+'				inst.InsertDecl decl.Copy(), True
+'			End If
+'		Next
 
 
 		If Not declImported Then
 		If Not declImported Then
 			inst.scope = _env.ModuleScope()
 			inst.scope = _env.ModuleScope()
@@ -2680,9 +2789,11 @@ End Rem
 
 
 		'Semant superclass		
 		'Semant superclass		
 		If superTy
 		If superTy
-			'superClass=superTy.FindClass()
+			Local cb:TClassDeclCallback = New TClassDeclCallback
+			cb.decl = Self
+			
 			attrs :| DECL_CYCLIC
 			attrs :| DECL_CYCLIC
-			superClass=superTy.SemantClass()
+			superClass=superTy.SemantClass(cb)
 			attrs :~ DECL_CYCLIC
 			attrs :~ DECL_CYCLIC
 			If superClass.IsInterface() Then
 			If superClass.IsInterface() Then
 				If Not IsExtern() Or Not superClass.IsExtern() Err superClass.ToString()+" is an interface, not a class."
 				If Not IsExtern() Or Not superClass.IsExtern() Err superClass.ToString()+" is an interface, not a class."
@@ -2742,18 +2853,7 @@ End Rem
 		'If IsTemplateInst()
 		'If IsTemplateInst()
 		'	Return
 		'	Return
 		'EndIf
 		'EndIf
-		
-		'Are we abstract?
-		If Not IsAbstract()
-			For Local decl:TDecl=EachIn _decls
-				Local fdecl:TFuncDecl=TFuncDecl( decl )
-				If fdecl And fdecl.IsAbstract()
-					attrs:|DECL_ABSTRACT
-					Exit
-				EndIf
-			Next
-		EndIf
-		
+				
 		If Not lastOffset And superClass Then
 		If Not lastOffset And superClass Then
 			lastOffset = superClass.LastOffset
 			lastOffset = superClass.LastOffset
 		End If
 		End If
@@ -2895,45 +2995,23 @@ End Rem
 		PushErr errInfo
 		PushErr errInfo
 		
 		
 		If Not IsInterface()
 		If Not IsInterface()
-			'
-			'check for duplicate fields! - BlitzMax supports fields with the same name in subclasses..
-			'
-			'For Local decl:TDecl=EachIn Semanted()
-			'	Local fdecl:TFieldDecl=TFieldDecl( decl )
-			'	If Not fdecl Continue
-			'	Local cdecl:TClassDecl=superClass
-			'	While cdecl
-			'		For Local decl:TDecl=EachIn cdecl.Semanted()
-			'			If decl.ident=fdecl.ident Err "Field '"+fdecl.ident+"' in class "+ToString()+" overrides existing declaration in class "+cdecl.ToString()
-			'		Next
-			'		cdecl=cdecl.superClass
-			'	Wend
-			'Next
-			'
-			'Check we implement all abstract methods!
-			'
+
+			' BlitzMax types are promoted to Abstract if they have an abstract method
+			If Not IsAbstract()
+				For Local fdecl:TFuncDecl = EachIn GetAllFuncDecls()
+					If fdecl.IsMethod() And fdecl.IsAbstract()
+						attrs:|DECL_ABSTRACT
+					End If
+				Next
+			End If
+
+			' Check we implement all abstract methods!
 			If IsInstanced()
 			If IsInstanced()
-				Local cdecl:TClassDecl=Self
-				Local impls:TList=New TList'<TFuncDecl>
-				While cdecl
-					For Local decl:TFuncDecl=EachIn cdecl.SemantedMethods()
-						If decl.IsAbstract()
-							Local found:Int
-							For Local decl2:TFuncDecl=EachIn impls
-								If decl.IdentLower() = decl2.IdentLower() And decl2.EqualsFunc( decl )
-									found=True
-									Exit
-								EndIf
-							Next
-							If Not found
-								Err "Can't create instance of type "+ToString()+" due to abstract method "+decl.ToString()+"."
-							EndIf
-						Else
-							impls.AddLast decl
-						EndIf
-					Next
-					cdecl=cdecl.superClass
-				Wend
+				For Local fdecl:TFuncDecl = EachIn GetAllFuncDecls()
+					If fdecl.IsAbstract() Then
+						Err "Can't create instance of type "+ToString()+" due to abstract "+fdecl.ToString()+"."
+					End If
+				Next
 			EndIf
 			EndIf
 			'
 			'
 			'Check we implement all interface methods!
 			'Check we implement all interface methods!
@@ -3192,6 +3270,10 @@ Type TDefDataDecl Extends TDecl
 	
 	
 End Type
 End Type
 
 
+Type TTryStmtDecl Extends TBlockDecl
+	Field tryStmt:TTryStmt
+End Type
+
 Const MODULE_STRICT:Int=1
 Const MODULE_STRICT:Int=1
 Const MODULE_SUPERSTRICT:Int=2
 Const MODULE_SUPERSTRICT:Int=2
 Const MODULE_ACTUALMOD:Int=4
 Const MODULE_ACTUALMOD:Int=4
@@ -3301,7 +3383,7 @@ Type TModuleDecl Extends TScopeDecl
 		
 		
 			For Local mdecl:TModuleDecl = EachIn _getDeclTreeCache
 			For Local mdecl:TModuleDecl = EachIn _getDeclTreeCache
 
 
-				If ident = mdecl.ident
+				If ident = mdecl.ident And mdecl <> Self
 					_getDeclCache.Insert(ident, mdecl)
 					_getDeclCache.Insert(ident, mdecl)
 					Return mdecl
 					Return mdecl
 				End If
 				End If
@@ -3674,3 +3756,25 @@ Type TStringConst
 	Field count:Int
 	Field count:Int
 
 
 End Type
 End Type
+
+Type TTemplateDets
+
+	Field instArgs:TType[]
+	Field args:TTemplateArg[]
+
+	Method Create:TTemplateDets(instArgs:TType[], args:TTemplateArg[])
+		Self.instArgs = instArgs
+		Self.args = args
+		Return Self
+	End Method
+
+End Type
+
+Type TGenProcessor Abstract
+
+	Global processor:TGenProcessor
+
+	Method ParseGeneric:Object(templ:TTemplateRecord, dets:TTemplateDets)
+	End Method
+	
+End Type

+ 75 - 8
expr.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 '
 '
@@ -163,6 +163,16 @@ Type TExpr
 						stmt.exprType = TNewObjectExpr(args[i]).ty
 						stmt.exprType = TNewObjectExpr(args[i]).ty
 						args[i] = stmt
 						args[i] = stmt
 					End If
 					End If
+
+					' passing a non volatile local as Var from within a Try block?					
+					If TVarExpr(args[i]) Then
+						Local ldecl:TLocalDecl = TLocalDecl(TVarExpr(args[i]).decl)
+						If ldecl Then
+							If Not ldecl.volatile And Not ldecl.declaredInTry And _env.FindTry() Then
+								ldecl.volatile = True
+							End If
+						End If
+					End If
 				End If
 				End If
 				
 				
 				If (funcDecl.argDecls[i].ty._flags & TType.T_VAR) And Not (funcDecl.argDecls[i].ty.EqualsType(args[i].exprType)) Then
 				If (funcDecl.argDecls[i].ty._flags & TType.T_VAR) And Not (funcDecl.argDecls[i].ty.EqualsType(args[i].exprType)) Then
@@ -201,6 +211,7 @@ Type TExpr
 				If TObjectType(rhs) And TObjectType(rhs).classDecl.ident = "Object" Then
 				If TObjectType(rhs) And TObjectType(rhs).classDecl.ident = "Object" Then
 					Return rhs
 					Return rhs
 				End If
 				End If
+				Return New TStringType
 			Else
 			Else
 				Return New TStringType
 				Return New TStringType
 			End If
 			End If
@@ -814,6 +825,8 @@ Type TNewObjectExpr Extends TExpr
 		Local it:TIdentType = TIdentType(ty)
 		Local it:TIdentType = TIdentType(ty)
 		Local iArgs:TExpr[] = SemantArgs(CopyArgs(args))
 		Local iArgs:TExpr[] = SemantArgs(CopyArgs(args))
 
 
+		Local isNewSelf:Int = (it And it.ident = "self")
+		
 		ty=ty.Semant(True)
 		ty=ty.Semant(True)
 		If Not ty Then
 		If Not ty Then
 			' maybe it's an instance of a type ?
 			' maybe it's an instance of a type ?
@@ -850,7 +863,8 @@ Type TNewObjectExpr Extends TExpr
 
 
 		If Not instanceExpr Then
 		If Not instanceExpr Then
 			If classDecl.IsInterface() Err "Cannot create instance of an interface."
 			If classDecl.IsInterface() Err "Cannot create instance of an interface."
-			If classDecl.IsAbstract() Err "Cannot create instance of an abstract class."
+			If classDecl.IsAbstract() Err "Cannot create instance of abstract type " + classDecl.ToString() + ..
+				", which is either declared Abstract or has (or inherits) an abstract Method."
 		End If
 		End If
 		'If classDecl.IsTemplateArg() Err "Cannot create instance of a generic argument."
 		'If classDecl.IsTemplateArg() Err "Cannot create instance of a generic argument."
 		If classDecl.args And Not classDecl.instanceof Err "Cannot create instance of a generic class."
 		If classDecl.args And Not classDecl.instanceof Err "Cannot create instance of a generic class."
@@ -876,7 +890,11 @@ Type TNewObjectExpr Extends TExpr
 			End If
 			End If
 		EndIf
 		EndIf
 
 
-		classDecl.attrs:|CLASS_INSTANCED
+		' New Self doesn't necessarily create an instance of ourself - we might be an instance of
+		' a subclass at the time...
+		If Not isNewSelf Then
+			classDecl.attrs:|CLASS_INSTANCED
+		End If
 
 
 		If TClassType(ty) Then
 		If TClassType(ty) Then
 			exprType=New TObjectType.Create(TClassType(ty).classDecl)
 			exprType=New TObjectType.Create(TClassType(ty).classDecl)
@@ -1486,6 +1504,11 @@ Type TCastExpr Extends TExpr
 			Return Self
 			Return Self
 		End If
 		End If
 
 
+		If TObjectType(ty) And TObjectType(src) And TObjectType(ty).classdecl.IsInterface() And flags & CAST_EXPLICIT Then
+			exprType = ty
+			Return Self
+		End If
+
 		If Not exprType
 		If Not exprType
 			Err "Unable to convert from "+src.ToString()+" to "+ty.ToString()+"."
 			Err "Unable to convert from "+src.ToString()+" to "+ty.ToString()+"."
 		EndIf
 		EndIf
@@ -1593,6 +1616,25 @@ Type TUnaryExpr Extends TExpr
 	Method Semant:TExpr()
 	Method Semant:TExpr()
 		If exprType Return Self
 		If exprType Return Self
 
 
+		expr = expr.Semant()
+
+		' operator overload?
+		If TObjectType(expr.exprType) And (op = "+" Or op = "-" Or op = "~~") Then
+			'Local args:TExpr[] = [rhs]
+			Try
+				Local decl:TFuncDecl = TFuncDecl(TObjectType(expr.exprType).classDecl.FindFuncDecl(op, Null,,,,True,SCOPE_CLASS_HEIRARCHY))
+				If decl Then
+					Return New TInvokeMemberExpr.Create( expr, decl, Null ).Semant()
+				End If
+			Catch error:String
+				If error.StartsWith("Compile Error") Then
+					Throw error
+				Else
+					Err "Operator " + op + " cannot be used with Objects."
+				End If
+			End Try
+		End If
+
 		Select op
 		Select op
 		Case "+","-"
 		Case "+","-"
 			expr=expr.Semant()
 			expr=expr.Semant()
@@ -1782,8 +1824,16 @@ Type TBinaryMathExpr Extends TBinaryExpr
 			Select op
 			Select op
 			Case "^" Return x^y
 			Case "^" Return x^y
 			Case "*" Return x*y
 			Case "*" Return x*y
-			Case "/" Return x/y
-			Case "mod" Return x Mod y
+			Case "/" 
+				If Not y Then
+					Err "Integer division by zero"
+				End If
+				Return x/y
+			Case "mod"
+				If Not y Then
+					Err "Integer division by zero"
+				End If
+				Return x Mod y
 			Case "shl" Return x Shl y
 			Case "shl" Return x Shl y
 			Case "shr" Return x Shr y
 			Case "shr" Return x Shr y
 			Case "+" Return x + y
 			Case "+" Return x + y
@@ -1797,8 +1847,16 @@ Type TBinaryMathExpr Extends TBinaryExpr
 			Select op
 			Select op
 			Case "^" Return x^y
 			Case "^" Return x^y
 			Case "*" Return x*y
 			Case "*" Return x*y
-			Case "/" Return x/y
-			Case "mod" Return x Mod y
+			Case "/"
+				If Not y Then
+					Err "Integer division by zero"
+				End If
+				Return x/y
+			Case "mod"
+				If Not y Then
+					Err "Integer division by zero"
+				End If
+				Return x Mod y
 			Case "shl" Return x Shl y
 			Case "shl" Return x Shl y
 			Case "shr" Return x Shr y
 			Case "shr" Return x Shr y
 			Case "+" Return x + y
 			Case "+" Return x + y
@@ -2504,8 +2562,16 @@ Type TIdentExpr Extends TExpr
 		End If
 		End If
 		
 		
 		If vdecl
 		If vdecl
+		
+			If op And TLocalDecl( vdecl )
+
+				Local ldecl:TLocalDecl = TLocalDecl( vdecl )
+
+				If Not ldecl.volatile And Not ldecl.declaredInTry And scope.FindTry() Then
+					ldecl.volatile = True
+				End If
 
 
-			If TConstDecl( vdecl )
+			Else If TConstDecl( vdecl )
 '				If rhs Err "Constant '"+ident+"' cannot be modified."
 '				If rhs Err "Constant '"+ident+"' cannot be modified."
 '				Return New TConstExpr.Create( vdecl.ty,TConstDecl( vdecl ).value ).Semant()
 '				Return New TConstExpr.Create( vdecl.ty,TConstDecl( vdecl ).value ).Semant()
 				If rhs Err "Constant '"+ident+"' cannot be modified."
 				If rhs Err "Constant '"+ident+"' cannot be modified."
@@ -2724,6 +2790,7 @@ Type TIdentExpr Extends TExpr
 			If expr And Not static Then
 			If expr And Not static Then
 				Return New TInvokeMemberExpr.Create( expr,fdecl,args ).Semant()
 				Return New TInvokeMemberExpr.Create( expr,fdecl,args ).Semant()
 			Else
 			Else
+				If fdecl.IsStatic() And fdecl.IsAbstract() Err "Cannot call abstract " + fdecl.ToString()
 				Return New TInvokeExpr.Create( fdecl,args, funcCall ).Semant()
 				Return New TInvokeExpr.Create( fdecl,args, funcCall ).Semant()
 			End If
 			End If
 		EndIf
 		EndIf

+ 1 - 1
iparser.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' 
 ' 

+ 2 - 2
options.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 '
 '
@@ -25,7 +25,7 @@ SuperStrict
 
 
 Import "base.configmap.bmx"
 Import "base.configmap.bmx"
 
 
-Const version:String = "0.92"
+Const version:String = "0.94"
 
 
 Const BUILDTYPE_APP:Int = 0
 Const BUILDTYPE_APP:Int = 0
 Const BUILDTYPE_MODULE:Int = 1
 Const BUILDTYPE_MODULE:Int = 1

+ 99 - 24
parser.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 '
 '
@@ -336,7 +336,7 @@ Type TIncbin
 End Type
 End Type
 
 
 '***** Parser *****
 '***** Parser *****
-Type TParser
+Type TParser Extends TGenProcessor
 
 
 	Field _toker:TToker
 	Field _toker:TToker
 	Field _toke:String
 	Field _toke:String
@@ -514,7 +514,7 @@ Type TParser
 
 
 	Method ParseIdentType:TIdentType()
 	Method ParseIdentType:TIdentType()
 		Local id$=ParseIdent()
 		Local id$=ParseIdent()
-'DebugLog "ParseIdentType : " + id
+
 		If CParse( "." ) id:+"."+ParseIdent()
 		If CParse( "." ) id:+"."+ParseIdent()
 		If CParse( "." ) id:+"."+ParseIdent()
 		If CParse( "." ) id:+"."+ParseIdent()
 
 
@@ -522,8 +522,19 @@ Type TParser
 		If CParse( "<" )
 		If CParse( "<" )
 			Local nargs:Int
 			Local nargs:Int
 			Repeat
 			Repeat
-				'Local arg:TIdentType=ParseIdentType()
 				Local arg:TType = ParseType()
 				Local arg:TType = ParseType()
+				
+				Repeat
+					If (_toke = "[" Or _toke = "[]") And IsArrayDef()
+						arg = ParseArrayType(arg)
+					Else If _toke = "(" Then
+						Local argDecls:TArgDecl[] = ParseFuncParamDecl()
+						arg = New TFunctionPtrType.Create(New TFuncDecl.CreateF("", arg, argDecls, FUNC_PTR))
+					Else
+						Exit
+					End If
+				Forever
+				
 				If args.Length=nargs args=args+ New TType[10]
 				If args.Length=nargs args=args+ New TType[10]
 				args[nargs]=arg
 				args[nargs]=arg
 				nargs:+1
 				nargs:+1
@@ -2022,7 +2033,11 @@ End Rem
 	Method ParseTryStmt()
 	Method ParseTryStmt()
 		Parse "try"
 		Parse "try"
 
 
-		Local block:TBlockDecl=New TBlockDecl.Create( _block )
+		Local tryStmtDecl:TTryStmtDecl = TTryStmtDecl(New TTryStmtDecl.Create( _block ))
+		
+		PushBlock tryStmtDecl
+
+		Local block:TBlockDecl=New TBlockDecl.Create( tryStmtDecl )
 		Local catches:TList=New TList
 		Local catches:TList=New TList
 		Local finallyStmt:TFinallyStmt = Null
 		Local finallyStmt:TFinallyStmt = Null
 
 
@@ -2068,16 +2083,23 @@ End Rem
 			End If
 			End If
 		Wend
 		Wend
 
 
-		PopBlock
-		
 		If catches.Count() = 0 And Not finallyStmt Then Err "Expecting 'Catch' or 'Finally'."
 		If catches.Count() = 0 And Not finallyStmt Then Err "Expecting 'Catch' or 'Finally'."
 		
 		
+		PopBlock ' try block
+		
 		If Not CParse("endtry") Then
 		If Not CParse("endtry") Then
 			NextToke
 			NextToke
 			CParse "try"
 			CParse "try"
 		End If
 		End If
 
 
-		_block.AddStmt New TTryStmt.Create( block,TCatchStmt[](catches.ToArray()),finallyStmt )
+		PopBlock ' tryStmtDecl
+		
+		Local tryStmt:TTryStmt = New TTryStmt.Create(block,TCatchStmt[](catches.ToArray()), finallyStmt)
+
+		tryStmtDecl.tryStmt = tryStmt
+
+		_block.AddStmt tryStmt
+		
 	End Method
 	End Method
 
 
 	Method ParseThrowStmt()
 	Method ParseThrowStmt()
@@ -2666,9 +2688,9 @@ End Rem
 				NextToke
 				NextToke
 				
 				
 				Select t
 				Select t
-					Case "*","/","+","-","&","|","~~"
+					Case "*","/","+","-","&","|","~~","^"
 						id = t
 						id = t
-					Case ":*",":/",":+",":-",":&",":|",":~~"
+					Case ":*",":/",":+",":-",":&",":|",":~~",":^"
 						id = t
 						id = t
 					Case "<",">"',"="',"<=",">=","=","<>"
 					Case "<",">"',"="',"<=",">=","=","<>"
 						If CParse("=") Then
 						If CParse("=") Then
@@ -2724,9 +2746,9 @@ End Rem
 			Local fdecl:TFuncDecl = TFunctionPtrType(ty).func
 			Local fdecl:TFuncDecl = TFunctionPtrType(ty).func
 			ty = fdecl.retTypeExpr
 			ty = fdecl.retTypeExpr
 			args = fdecl.argDecls
 			args = fdecl.argDecls
+			attrs :| (fdecl.attrs & DECL_API_FLAGS)
 		End If
 		End If
 		
 		
-		
 		If CParse( "nodebug" ) Then
 		If CParse( "nodebug" ) Then
 			attrs :| DECL_NODEBUG
 			attrs :| DECL_NODEBUG
 		End If
 		End If
@@ -2889,13 +2911,14 @@ End Rem
 		Local api:String = ParseStringLit().ToLower()
 		Local api:String = ParseStringLit().ToLower()
 		
 		
 		If api = "os" Then
 		If api = "os" Then
-?win32
-			api = "win32"
-?macos
-			api = "macos"
-?linux
-			api = "linux"
-?
+			Select opt_platform
+				Case "macos", "osx", "ios"
+					api = "macos"
+				Case "linux", "android", "raspberrypi"
+					api = "linux"
+				Case "win32"
+					api = "win32"
+			End Select
 		End If
 		End If
 
 
 		Select api
 		Select api
@@ -2944,7 +2967,7 @@ End Rem
 	End Method
 	End Method
 	
 	
 
 
-	Method ParseClassDecl:TClassDecl( toke$,attrs:Int )
+	Method ParseClassDecl:TClassDecl( toke$,attrs:Int, templateDets:TTemplateDets = Null )
 		SetErr
 		SetErr
 
 
 		Local calculatedStartLine:Int = _toker.Line()
 		Local calculatedStartLine:Int = _toker.Line()
@@ -2986,9 +3009,9 @@ End Rem
 				Local arg:TTemplateArg = New TTemplateArg
 				Local arg:TTemplateArg = New TTemplateArg
 				arg.ident = ParseIdent()
 				arg.ident = ParseIdent()
 				
 				
-				If CParse("extends") Then
-					arg.superTy = ParseIdentType()
-				End If
+'				If CParse("extends") Then
+'					arg.superTy = ParseIdentType()
+'				End If
 				
 				
 				args.AddLast arg
 				args.AddLast arg
 
 
@@ -2996,6 +3019,34 @@ End Rem
 			'args=args[..nargs]
 			'args=args[..nargs]
 
 
 			Parse ">"
 			Parse ">"
+
+			If CParse( "where" ) Then
+'DebugStop
+				Repeat
+					Local argIdent:String = ParseIdent()
+					
+					Parse("extends")
+					
+					Local found:Int
+					For Local arg:TTemplateArg = EachIn args
+						If arg.ident = argIdent Then
+						
+							Repeat
+							
+								arg.ExtendsType(ParseIdentType())
+							
+							Until Not CParse("and")
+						
+							found = True
+							Exit
+						EndIf
+					Next
+					If Not found Then
+						Err "Use of undeclared type '" + argIdent + "'."
+					End If
+					
+				Until Not CParse(",")
+			End If
 		EndIf
 		EndIf
 
 
 		If CParse( "extends" )
 		If CParse( "extends" )
@@ -3234,7 +3285,13 @@ End Rem
 				Local decl:TFuncDecl=ParseFuncDecl( _toke,decl_attrs,classDecl )
 				Local decl:TFuncDecl=ParseFuncDecl( _toke,decl_attrs,classDecl )
 				classDecl.InsertDecl decl
 				classDecl.InsertDecl decl
 			Case "type"
 			Case "type"
-				classDecl.InsertDecl ParseClassDecl( _toke,DECL_NESTED)
+				If templateDets Then
+					Local cdecl:TClassDecl = ParseClassDecl( _toke,DECL_NESTED, templateDets)
+					cdecl = cdecl.GenClassInstance(templateDets.instArgs, False, Null, templateDets)
+					classDecl.InsertDecl cdecl, True
+				Else
+					classDecl.InsertDecl ParseClassDecl( _toke,DECL_NESTED)
+				End If
 			Default
 			Default
 				Err "Syntax error - expecting class member declaration, not '" + _toke + "'"
 				Err "Syntax error - expecting class member declaration, not '" + _toke + "'"
 			End Select
 			End Select
@@ -3687,6 +3744,24 @@ End Rem
 		Return attrs
 		Return attrs
 	End Method
 	End Method
 
 
+	Method ParseGeneric:Object(templateSource:TTemplateRecord, templateDets:TTemplateDets)
+		Local toker:TToker = New TToker.Create(templateSource.file, templateSource.source, False, templateSource.start)
+		Local parser:TParser = New TParser.Create( toker, _appInstance )
+		
+		Local m:TModuleDecl = New TModuleDecl
+		parser._module = m
+		
+		Local cdecl:TClassDecl = Null
+		
+		Select parser._toke
+		Case "type"
+			cdecl = parser.ParseClassDecl(parser._toke,0, templateDets )
+		Case "interface"
+			cdecl = parser.ParseClassDecl(parser._toke, CLASS_INTERFACE|DECL_ABSTRACT, templateDets )
+		End Select
+		
+		Return cdecl
+	End Method
 
 
 	Method ParseMain()
 	Method ParseMain()
 
 
@@ -3993,7 +4068,7 @@ End Rem
 			con = 0
 			con = 0
 			Try
 			Try
 				If Eval( toker,New TIntType ) = "1" con = 1
 				If Eval( toker,New TIntType ) = "1" con = 1
-			Catch error:String
+			Catch Error:String
 				con = 0
 				con = 0
 			End Try
 			End Try
 
 

+ 11 - 2
stmt.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 '
 '
@@ -77,6 +77,10 @@ Type TDeclStmt Extends TStmt
 	End Method
 	End Method
 	
 	
 	Method OnSemant()
 	Method OnSemant()
+		If TLocalDecl(decl) And _env.FindTry() Then
+			TLocalDecl(decl).declaredInTry = True
+		End If
+		
 		decl.Semant
 		decl.Semant
 		' if scope is already set, don't try to add it to the current scope.
 		' if scope is already set, don't try to add it to the current scope.
 		If Not decl.scope Then
 		If Not decl.scope Then
@@ -116,6 +120,7 @@ Type TAssignStmt Extends TStmt
 			TIdentExpr(rhs).isRhs = True
 			TIdentExpr(rhs).isRhs = True
 		End If
 		End If
 		rhs=rhs.Semant()
 		rhs=rhs.Semant()
+
 		lhs=lhs.SemantSet( op,rhs )
 		lhs=lhs.SemantSet( op,rhs )
 		If TInvokeExpr( lhs ) Or TInvokeMemberExpr( lhs )
 		If TInvokeExpr( lhs ) Or TInvokeMemberExpr( lhs )
 			rhs=Null
 			rhs=Null
@@ -550,7 +555,11 @@ Type TRepeatStmt Extends TLoopStmt
 	End Method
 	End Method
 
 
 	Method OnCopy:TStmt( scope:TScopeDecl )
 	Method OnCopy:TStmt( scope:TScopeDecl )
-		Return New TRepeatStmt.Create( block.CopyBlock( scope ),expr.Copy(),TLoopLabelDecl(loopLabel.Copy()) )
+		If loopLabel Then
+			Return New TRepeatStmt.Create( block.CopyBlock( scope ),expr.Copy(),TLoopLabelDecl(loopLabel.Copy()) )
+		Else
+			Return New TRepeatStmt.Create( block.CopyBlock( scope ),expr.Copy(),Null )
+		End If
 	End Method
 	End Method
 	
 	
 	Method OnSemant()
 	Method OnSemant()

+ 1 - 1
stringbuffer_common.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2016-2017 Bruce A Henderson
+' Copyright (c) 2016-2018 Bruce A Henderson
 ' 
 ' 
 ' Permission is hereby granted, free of charge, to any person obtaining a copy
 ' Permission is hereby granted, free of charge, to any person obtaining a copy
 ' of this software and associated documentation files (the "Software"), to deal
 ' of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
stringbuffer_core.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2016-2017 Bruce A Henderson
+' Copyright (c) 2016-2018 Bruce A Henderson
 ' 
 ' 
 ' Permission is hereby granted, free of charge, to any person obtaining a copy
 ' Permission is hereby granted, free of charge, to any person obtaining a copy
 ' of this software and associated documentation files (the "Software"), to deal
 ' of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
stringbuffer_glue.c

@@ -1,5 +1,5 @@
 /*
 /*
-  Copyright (c) 2016-2017 Bruce A Henderson
+  Copyright (c) 2016-2018 Bruce A Henderson
  
  
   Permission is hereby granted, free of charge, to any person obtaining a copy
   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   of this software and associated documentation files (the "Software"), to deal

+ 2 - 2
toker.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 '
 '
@@ -49,7 +49,7 @@ Type TToker
 		"and,or,shl,shr,sar,end,if,then,else,elseif,endif,while,wend,repeat,until,forever,for,to,step," + ..
 		"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,finally,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," + ..
 		"endfunction,endtype,endextern,endtry,endwhile,pi,release,defdata,readdata,restoredata,interface," + ..
-		"endinterface,implements,size_t,uint,ulong,struct,endstruct,operator"
+		"endinterface,implements,size_t,uint,ulong,struct,endstruct,operator,where"
 	Global _keywords:TMap
 	Global _keywords:TMap
 
 
 	Field _path$
 	Field _path$

+ 1 - 1
transform.c

@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017 Bruce A Henderson
+/* Copyright (c) 2014-2018 Bruce A Henderson
 
 
   This software is provided 'as-is', without any express or implied
   This software is provided 'as-is', without any express or implied
   warranty. In no event will the authors be held liable for any damages
   warranty. In no event will the authors be held liable for any damages

+ 5 - 1
translator.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 '
 '
@@ -380,6 +380,8 @@ Type TTranslator
 				Return "_or"
 				Return "_or"
 			Case "~~"
 			Case "~~"
 				Return "_xor"
 				Return "_xor"
+			Case "^"
+				Return "_pow"
 			Case ":*"
 			Case ":*"
 				Return "_muleq"
 				Return "_muleq"
 			Case ":/"
 			Case ":/"
@@ -394,6 +396,8 @@ Type TTranslator
 				Return "_oreq"
 				Return "_oreq"
 			Case ":~~"
 			Case ":~~"
 				Return "_xoreq"
 				Return "_xoreq"
+			Case ":^"
+				Return "_poweq"
 			Case "<"
 			Case "<"
 				Return "_lt"
 				Return "_lt"
 			Case "<="
 			Case "<="

+ 34 - 19
type.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2013-2017 Bruce A Henderson
+' Copyright (c) 2013-2018 Bruce A Henderson
 '
 '
 ' Based on the public domain Monkey "trans" by Mark Sibly
 ' Based on the public domain Monkey "trans" by Mark Sibly
 '
 '
@@ -52,7 +52,7 @@ Type TType
 		Return T_MAX_DISTANCE
 		Return T_MAX_DISTANCE
 	End Method
 	End Method
 	
 	
-	Method Semant:TType(option:Int = False)
+	Method Semant:TType(option:Int = False, callback:TCallback = Null)
 		Return Self
 		Return Self
 	End Method
 	End Method
 
 
@@ -1352,7 +1352,7 @@ Type TStringType Extends TType
 		Return cdecl
 		Return cdecl
 	End Method
 	End Method
 	
 	
-	Method Semant:TType(option:Int = 0)
+	Method Semant:TType(option:Int = 0, callback:TCallback = Null)
 		GetClass()
 		GetClass()
 		Return Self
 		Return Self
 	End Method
 	End Method
@@ -1378,9 +1378,10 @@ Type TArrayType Extends TType
 	Field elemType:TType
 	Field elemType:TType
 	Field dims:Int
 	Field dims:Int
 	
 	
-	Method Create:TArrayType( elemType:TType, dims:Int = 1 )
+	Method Create:TArrayType( elemType:TType, dims:Int = 1, flags:Int = 0 )
 		Self.elemType=elemType
 		Self.elemType=elemType
 		Self.dims = dims
 		Self.dims = dims
+		Self._flags = flags
 		Return Self
 		Return Self
 	End Method
 	End Method
 	
 	
@@ -1400,9 +1401,9 @@ Type TArrayType Extends TType
 		Return (arrayType And dims = arrayType.dims And ( TVoidType( elemType ) Or (TObjectType(elemType) And elemType.EqualsType( arrayType.elemType ) Or elemType.ExtendsType( arrayType.elemType )))) Or IsPointerType(ty, 0, TType.T_POINTER) <> Null Or (TObjectType( ty ) And TObjectType( ty ).classDecl.ident="Object")
 		Return (arrayType And dims = arrayType.dims And ( TVoidType( elemType ) Or (TObjectType(elemType) And elemType.EqualsType( arrayType.elemType ) Or elemType.ExtendsType( arrayType.elemType )))) Or IsPointerType(ty, 0, TType.T_POINTER) <> Null Or (TObjectType( ty ) And TObjectType( ty ).classDecl.ident="Object")
 	End Method
 	End Method
 	
 	
-	Method Semant:TType(option:Int = False)
-		Local ty:TType=elemType.Semant()
-		If ty<>elemType Return New TArrayType.Create( ty, dims )
+	Method Semant:TType(option:Int = False, callback:TCallback = Null)
+		Local ty:TType=elemType.Semant(option, callback)
+		If ty<>elemType Return New TArrayType.Create( ty, dims, _flags )
 		Return Self
 		Return Self
 	End Method
 	End Method
 	
 	
@@ -1538,13 +1539,13 @@ Type TIdentType Extends TType
 	'End Method
 	'End Method
 	
 	
 	
 	
-	Method Semant:TType(ignoreNotFoundError:Int = 0)
+	Method Semant:TType(ignoreNotFoundError:Int = 0, callback:TCallback = Null)
 'If ident="IPair" DebugStop
 'If ident="IPair" DebugStop
 		If Not ident Return TType.nullObjectType
 		If Not ident Return TType.nullObjectType
 
 
 		Local targs:TType[args.Length]
 		Local targs:TType[args.Length]
 		For Local i:Int=0 Until args.Length
 		For Local i:Int=0 Until args.Length
-			targs[i]=args[i].Semant()
+			targs[i]=args[i].Semant(ignoreNotFoundError, callback)
 		Next
 		Next
 		
 		
 		Local tyid$,ty:TType
 		Local tyid$,ty:TType
@@ -1571,13 +1572,13 @@ Type TIdentType Extends TType
 			End If
 			End If
 			
 			
 			If Not ty Then
 			If Not ty Then
-				ty=_env.FindType( tyid,targs )
+				ty=_env.FindType( tyid,targs, callback )
 			End If
 			End If
 
 
 			' finally scan all modules for it
 			' finally scan all modules for it
 			If Not ty Then
 			If Not ty Then
 				For Local mdecl:TModuleDecl = EachIn _appInstance.globalImports.Values()
 				For Local mdecl:TModuleDecl = EachIn _appInstance.globalImports.Values()
-					ty=mdecl.FindType( tyid,targs )
+					ty=mdecl.FindType( tyid,targs, callback )
 					If ty Exit
 					If ty Exit
 				Next
 				Next
 			End If
 			End If
@@ -1606,7 +1607,7 @@ Type TIdentType Extends TType
 			End If
 			End If
 			
 			
 			If Not ty Then
 			If Not ty Then
-				ty=_env.FindType( tyid,targs )
+				ty=_env.FindType( tyid,targs, callback )
 			End If
 			End If
 			
 			
 			If Not ty Then
 			If Not ty Then
@@ -1614,7 +1615,7 @@ Type TIdentType Extends TType
 		
 		
 				' try scope search first
 				' try scope search first
 				tyid=id[..i]
 				tyid=id[..i]
-				ty=_env.FindType( tyid,targs )				
+				ty=_env.FindType( tyid,targs, callback )				
 
 
 				If Not ty Then
 				If Not ty Then
 					' no? now try module search
 					' no? now try module search
@@ -1622,7 +1623,7 @@ Type TIdentType Extends TType
 					Local mdecl:TModuleDecl=_env.FindModuleDecl( modid )
 					Local mdecl:TModuleDecl=_env.FindModuleDecl( modid )
 					If Not mdecl Err "Module '"+modid+"' not found"
 					If Not mdecl Err "Module '"+modid+"' not found"
 					tyid=id[i+1..]
 					tyid=id[i+1..]
-					ty=mdecl.FindType( tyid,targs )
+					ty=mdecl.FindType( tyid,targs, callback )
 				End If
 				End If
 			End If
 			End If
 		EndIf
 		EndIf
@@ -1650,8 +1651,8 @@ Type TIdentType Extends TType
 		Return ty
 		Return ty
 	End Method
 	End Method
 
 
-	Method SemantClass:TClassDecl()
-		Local ty:TObjectType=TObjectType( Semant() )
+	Method SemantClass:TClassDecl(callback:TCallback = Null)
+		Local ty:TObjectType=TObjectType( Semant(False, callback) )
 		If Not ty Err "Type is not a class"
 		If Not ty Err "Type is not a class"
 		Return ty.classDecl
 		Return ty.classDecl
 	End Method
 	End Method
@@ -1804,7 +1805,7 @@ Type TFunctionPtrType Extends TType
 		Return ty
 		Return ty
 	End Method
 	End Method
 
 
-	Method Semant:TType(option:Int = False)
+	Method Semant:TType(option:Int = False, callback:TCallback = Null)
 		func.Semant()
 		func.Semant()
 		Return Self
 		Return Self
 	End Method
 	End Method
@@ -2012,12 +2013,26 @@ End Type
 
 
 Type TTemplateArg
 Type TTemplateArg
 	Field ident:String
 	Field ident:String
-	Field superTy:TType
+	Field superTy:TType[]
+	
+	Method ExtendsType(ty:TType)
+		If Not superTy Then
+			superTy = New TType[0]
+		End If
+		
+		superTy :+ [ty]
+	End Method
 	
 	
 	Method ToString:String()
 	Method ToString:String()
 		Local s:String = ident
 		Local s:String = ident
 		If superTy Then
 		If superTy Then
-			s :+ " Extends " + superTy.ToString()
+			s :+ " Extends "
+			For Local i:Int = 0 Until superTy.length
+				If i Then
+					s:+ " And "
+				End If
+				s :+ superTy[i].ToString()
+			Next
 		End If
 		End If
 	End Method
 	End Method
 End Type
 End Type