ignore blank namespaces in codedom (tested w/google wsdl)

git-svn-id: fcce7d6ce0ac15bf24f68871b5145d46fc068279@2046 2c1201b4-01cd-e047-a400-b836ae1fbc61

#region license
// Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//     * Neither the name of Rodrigo B. de Oliveira nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

// authors:
// Arron Washington
// Ian MacLean (original C# version)

//See also:
//http://svn.myrealbox.com/viewcvs/trunk/mcs/class/System/Microsoft.CSharp/CSharpCodeGenerator.cs?view=auto
//http://svn.myrealbox.com/viewcvs/trunk/mcs/class/System/Microsoft.VisualBasic/VBCodeGenerator.cs?view=auto

namespace Boo.Lang.CodeDom

import System
import System.CodeDom
import System.CodeDom.Compiler
import System.IO
import System.Reflection
import System.Collections
import System.Text.RegularExpressions

class BooCodeGenerator(CodeGenerator):
	static newlinePattern = Regex("\\n",RegexOptions.Compiled)

	static whiteSpacePattern = Regex("(\\s*)",RegexOptions.Compiled)

	static primitives = { "System.Double" : "double",
						"System.Single" : "single",
						"System.Int32" : "int",
						"System.Int64" : "long",
						"System.Int16" : "short",
						"System.UInt16" : "ushort",
						"System.Boolean" : "bool",
						"System.Char" : "char",
						"System.String" : "string",
						"System.Object" : "object",
						"System.Void" : "void"}

	protected NullToken as string:
		get:
			return "null"

	protected override def OutputType(typeRef as CodeTypeReference):
		Output.Write(GetTypeOutput(typeRef))

	protected override def GenerateArrayCreateExpression(exp as CodeArrayCreateExpression) :
		if exp.Initializers.Count:
			Output.Write("(")
			OutputExpressionList(exp.Initializers)
			Output.Write(")")
		else:
			Output.Write("array(")
			OutputType(exp.CreateType)
			Output.Write(",")
			if exp.SizeExpression:
				GenerateExpression(exp)
			else:
				Output.Write(exp.Size)
			Output.Write(")")

	protected override def GenerateBaseReferenceExpression(e as CodeBaseReferenceExpression) :
		Output.Write("super")

	protected override def GenerateCastExpression(e as CodeCastExpression) :
		Output.Write("cast(")
		OutputType(e.TargetType)
		Output.Write(",")
		GenerateExpression(e.Expression)
		Output.Write(")")

	protected override def GenerateDelegateCreateExpression(e as CodeDelegateCreateExpression) :
		GenerateExpression(e.TargetObject)
		Output.Write(".${e.MethodName} as ")
		OutputType(e.DelegateType)

	protected override def GenerateFieldReferenceExpression(e as CodeFieldReferenceExpression):
		MemberReference(e.TargetObject, e.FieldName)

	protected override def GenerateArgumentReferenceExpression(e as CodeArgumentReferenceExpression) :
		Output.Write(e.ParameterName)

	protected override def GenerateVariableReferenceExpression(e as CodeVariableReferenceExpression) :
		Output.Write(e.VariableName)

	protected override def GenerateIndexerExpression(e as CodeIndexerExpression) :
		Indexer(e.TargetObject, e.Indices)

	protected override def GenerateArrayIndexerExpression(e as CodeArrayIndexerExpression) :
		Indexer(e.TargetObject, e.Indices)

	protected override def GenerateMethodInvokeExpression(e as CodeMethodInvokeExpression) :
		Invocation(e.Method, e.Parameters)

	protected override def GenerateMethodReferenceExpression(e as CodeMethodReferenceExpression) :
		MemberReference(e.TargetObject, e.MethodName)
	protected override def GenerateEventReferenceExpression(e as CodeEventReferenceExpression) :
		MemberReference(e.TargetObject, e.EventName)

	protected override def GenerateDelegateInvokeExpression(e as CodeDelegateInvokeExpression) :
		Invocation(e.TargetObject, e.Parameters)

	protected override def GenerateObjectCreateExpression(e as CodeObjectCreateExpression) :
		OutputType(e.CreateType)
		Output.Write("(")
		OutputExpressionList(e.Parameters)
		Output.Write(")")

	protected override def GeneratePropertyReferenceExpression(e as CodePropertyReferenceExpression) :
		MemberReference(e.TargetObject, e.PropertyName)

	protected override def GeneratePropertySetValueReferenceExpression(e as CodePropertySetValueReferenceExpression) :
		Output.Write("value")

	protected override def GenerateThisReferenceExpression(e as CodeThisReferenceExpression) :
		Output.Write("self")

	protected override def GenerateExpressionStatement(e as CodeExpressionStatement) :
		GenerateExpression(e.Expression)
		Output.WriteLine();

	protected override def GenerateIterationStatement(e as CodeIterationStatement) :
		GenerateStatement(e.InitStatement)
		Output.Write("while ")
		GenerateExpression(e.TestExpression)
		Output.Write(":")
		Indent++
		GenerateStatements(e.Statements)
		GenerateStatement(e.IncrementStatement)
		Indent--

	protected override def GenerateThrowExceptionStatement(e as CodeThrowExceptionStatement) :
		Output.Write("raise ")
		GenerateExpression(e.ToThrow)

	protected override def GenerateComment(comment as CodeComment) :
		//TODO: check comment.DocComment when boo doc format is available
		commentSymbol = "#"
		txt = comment.Text

		Output.Write(commentSymbol + " ")

		i = 0
		while i<len(txt):
			rawArrayIndexing:
				Output.Write(txt[i])
				if txt[i] == char('\r'):
					if i<len(txt)-1 and txt[i+1]==char('\n'):
						continue
					Output.Write(commentSymbol)
				elif txt[i] == char('\n'):
					Output.Write(commentSymbol)
			++i
		Output.WriteLine()

	protected override def GenerateMethodReturnStatement(e as CodeMethodReturnStatement) :
		Output.Write("return ")
		GenerateExpression(e.Expression)
		Output.WriteLine()

	protected override def GenerateConditionStatement(e as CodeConditionStatement) :
		Output.Write("if ")
		GenerateExpression(e.Condition)
		Output.WriteLine(":")
		Indent++
		GenerateStatements(e.TrueStatements)
		Output.WriteLine ("pass") if len(e.TrueStatements) == 0
		Indent--
		return unless e.FalseStatements.IsValid()
		Output.WriteLine("else:")
		Indent++
		GenerateStatements(e.FalseStatements)
		Output.WriteLine ("pass") if len(e.TrueStatements) == 0
		Indent--

	protected override def GenerateTryCatchFinallyStatement(e as CodeTryCatchFinallyStatement) :
		Output.Write("try:")
		Indent++
		GenerateStatements(e.TryStatements)
		Indent--
		for exp as CodeCatchClause in e.CatchClauses:
			Output.Write("except ")
			Output.Write("${exp.LocalName} as ")
			OutputType(exp.CatchExceptionType)
			Output.Write(":")
			Indent++
			GenerateStatements(exp.Statements)
			Indent--
		GenerateStatements(e.FinallyStatements)

	protected override def GenerateAssignStatement(e as CodeAssignStatement) :
		GenerateExpression(e.Left)
		Output.Write(" = ")
		GenerateExpression(e.Right)
		Output.WriteLine()
	protected override def GenerateAttachEventStatement(e as CodeAttachEventStatement) :
		GenerateExpression(e.Event)
		Output.Write(" += ")
		GenerateExpression(e.Listener)
		Output.WriteLine()
	protected override def GenerateRemoveEventStatement(e as CodeRemoveEventStatement) :
		GenerateExpression(e.Event)
		Output.Write(" -= ")
		GenerateExpression(e.Listener)
		Output.WriteLine()
	protected override def GenerateGotoStatement(e as CodeGotoStatement) :
		Output.WriteLine("goto ${e.Label}")
	protected override def GenerateLabeledStatement(e as CodeLabeledStatement) :
		Output.WriteLine(":${e.Label}")
		GenerateStatement(e.Statement) if e.Statement
	protected override def GenerateVariableDeclarationStatement(e as CodeVariableDeclarationStatement) :
		Output.Write("${e.Name} as ")
		OutputType(e.Type)
		if e.InitExpression:
			Output.Write(" = ")
			GenerateExpression(e.InitExpression)
		Output.WriteLine()
	protected override def GenerateLinePragmaStart(e as CodeLinePragma) :
		pass

	protected override def GenerateLinePragmaEnd(e as CodeLinePragma) :
		pass

	protected override def GenerateEvent(e as CodeMemberEvent, c as CodeTypeDeclaration) :

		if e.PrivateImplementationType:
			raise "Does not support private implementation type."
		if e.ImplementationTypes.IsValid():
			raise "Does not implement these types: ${join(e.ImplementationTypes)}"
		e.Attributes |= MemberAttributes.Final

		ModifiersAndAttributes(e)

		Output.Write("event ${e.Name} as ")
		OutputType(e.Type)
		Output.WriteLine()
	protected override def GenerateField(e as CodeMemberField) :

		ModifiersAndAttributes(e)
		Output.Write("${e.Name} as ")
		OutputType(e.Type)
		if e.InitExpression:
			Output.Write(" = ")
			GenerateExpression(e.InitExpression)
		Output.WriteLine()

	protected override def GenerateSnippetMember(e as CodeSnippetTypeMember) :
		OutputAttributeDeclarations(e.CustomAttributes) if e.CustomAttributes
		Output.Write(FixIndent(e.Text))

	protected override def GenerateSnippetExpression(e as CodeSnippetExpression) :
		//Output.Write("("+e.Value+")")
		Output.Write(e.Value)

	protected override def GenerateSnippetCompileUnit(e as CodeSnippetCompileUnit) :
		Output.Write(FixIndent(e.Value))

	protected override def GenerateSnippetStatement(e as CodeSnippetStatement) :
		Output.Write(FixIndent(e.Value))

	protected def FixIndent(code as string) as string:
		return string.Empty if code is null or code==string.Empty

		spacespertab = 4
		indentspaces = " "*spacespertab

		code = code.Replace("\t",indentspaces)

		//find first line that has non-whitespace and isn't a comment
		lines = newlinePattern.Split(code.Replace("\r\n", "\n"))
		foundfirst = false  //1st non-whitespace, non-commented line
		insidecomment = 0
		for line in lines:
			trimmed = line.Trim()
			if trimmed == string.Empty:
				continue

			startmultiline = trimmed.StartsWith("/*")

			//if not whitespace and not a comment...
			if (insidecomment <= 0 and
					not startmultiline and
					not trimmed.StartsWith("#") and
					not trimmed.StartsWith("//")):
				foundfirst = true
				first = line
				break //stop for loop

			//special stuff for handling multiline comments
			if startmultiline or insidecomment > 0:
				j = 0
				linelen = len(trimmed) - 1
				while j < linelen:
					rawArrayIndexing:
						c = trimmed[j]
					if c==char('/'):
						rawArrayIndexing:
							nextc = trimmed[j+1]
						if nextc==char('*'):
							++insidecomment
							++j
					elif c==char('*') and insidecomment > 0:
						rawArrayIndexing:
							nextc = trimmed[j+1]
						if nextc==char('/'):
							--insidecomment
							++j
					++j

		if not foundfirst:  //all whitespace or comments
			return code

		indentprefix = string.Empty
		//how much the code should be indented:
		indentprefix = " " * (Indent * spacespertab) if Indent > 0

		//how much the code actually is indented:
		indent = whiteSpacePattern.Match(first).Groups[0].Value

		//if code is properly indented, return now
		return code if indent == indentprefix

		buffer = System.Text.StringBuilder()
		sz = len(indent)
		firstline = true
		for line in lines:
			if not firstline: //indentedtextwriter will handle indenting first line
				buffer.Append(indentprefix)
			else:
				firstline = false
			if sz==0 or not line.StartsWith(indent):
				buffer.Append(line)
			else:
				buffer.Append(line[sz:])
			buffer.Append("\n")
		return buffer.ToString()

	protected override def GenerateEntryPointMethod(e as CodeEntryPointMethod, c as CodeTypeDeclaration) :
		Method(e, "Main")

	protected override def GenerateMethod(e as CodeMemberMethod, c as CodeTypeDeclaration) :
		Method(e, e.Name)

	protected override def GenerateProperty(e as CodeMemberProperty, c as CodeTypeDeclaration) :
		ModifiersAndAttributes(e)

		Output.Write(" ${e.Name} ")
		if len(e.Parameters) > 1:
			Output.Write("(")
			OutputParameters(e.Parameters)
			Output.Write(")")
		Output.Write(" as ")
		OutputType(e.Type)
		Output.WriteLine(":")
		Indent++
		if e.HasGet:
			Output.WriteLine("get:")
			Indent++
			GenerateStatements(e.GetStatements)
			passcheck(e.GetStatements)
			Indent--
			Output.WriteLine()
		if e.HasSet:
			Output.WriteLine("set:")
			Indent++
			GenerateStatements(e.SetStatements)
			passcheck(e.SetStatements)
			Indent--
			Output.WriteLine()
		Indent--
		Output.WriteLine()
	protected override def GenerateConstructor(e as CodeConstructor, c as CodeTypeDeclaration) :
		Method(e, "constructor")

	protected override def GenerateTypeConstructor(e as CodeTypeConstructor) :
		e.Attributes |= MemberAttributes.Static
		e.Parameters.Clear()
		Method(e, "constructor")

	protected override def GenerateTypeStart(e as CodeTypeDeclaration):
		Output.WriteLine()
		OutputAttributeDeclarations(e.CustomAttributes)
		Output.WriteLine()
		if e.TypeAttributes & TypeAttributes.Sealed:
			e.TypeAttributes = (e.TypeAttributes.ToInt() & ~TypeAttributes.Sealed.ToInt()).ToEnum(TypeAttributes)
			Output.Write("final ")
		if e isa CodeTypeDelegate:
			GenerateDelegate(e)
			return
		OutputTypeAttributes(e.TypeAttributes, e.IsStruct, e.IsEnum)
		Output.Write(" ${e.Name}(")
		for index in range(len(e.BaseTypes)):
			var as CodeTypeReference = e.BaseTypes[index]
			OutputType(var)
			continue unless index + 1 != e.BaseTypes.Count
			Output.Write(",")
		Output.Write("):")
		Indent++
		#Ah hah hah, yeah, no. Empty class.
		passcheck(e.Members)

	private def GenerateDelegate(e as CodeTypeDelegate):
		if e.TypeAttributes & TypeAttributes.NestedFamORAssem == TypeAttributes.Public:
			Output.Write("public ")
		Output.Write("callable ${e.Name}(")
		OutputParameters(e.Parameters)
		Output.Write(") as ")
		OutputType(e.ReturnType)

	protected override def GenerateTypeEnd(e as CodeTypeDeclaration) :
		Indent--

	protected override def GenerateNamespaceStart(e as CodeNamespace) :
		if e and e.Name and e.Name != string.Empty:
			Output.WriteLine("namespace ${e.Name}")

	protected override def GenerateNamespaceEnd(e as CodeNamespace) :
		pass

	protected override def GenerateNamespaceImport(e as CodeNamespaceImport) :
		Output.WriteLine("import ${e.Namespace}")

	protected override def GenerateAttributeDeclarationsStart(attributes as CodeAttributeDeclarationCollection) :
		Output.Write("[")

	protected override def GenerateAttributeDeclarationsEnd(attributes as CodeAttributeDeclarationCollection) :
		Output.Write("]")

	protected override def Supports(support as GeneratorSupport) as bool:
		return true

	protected override def IsValidIdentifier(value as string) as bool:
		return true

	protected override def CreateEscapedIdentifier(value as string) as string:
		return value

	protected override def CreateValidIdentifier(value as string) as string:
		return value

	protected override def GetTypeOutput(typeRef as CodeTypeReference):
		if typeRef.ArrayElementType:
			out = GetTypeOutput(typeRef.ArrayElementType)
		elif typeRef.BaseType in primitives:
			out = primitives[typeRef.BaseType]
		else:
			out = typeRef.BaseType

		if typeRef.ArrayRank > 0:
			if typeRef.ArrayRank > 1:
				return "(${out}, ${typeRef.ArrayRank})"
			return "(${out})"
		return out

	protected override def QuoteSnippetString(snippet as string) as string:
		s = snippet.Replace("\\", "\\\\")
		s = s.Replace("\"", "\\\"")
		s = s.Replace("\t", "\\t")
		s = s.Replace("\r", "\\r")
		s = s.Replace("\n", "\\n")
		return "\"" + s + "\""

	def Method(method as duck, name as string):
		ModifiersAndAttributes(method)
		Output.Write("def ${name} (")
		OutputParameters(method.Parameters)
		Output.Write(")")
		unless GetTypeOutput(method.ReturnType) == "void":
			Output.Write(" as ")
			OutputType(method.ReturnType)
			OutputAttributeDeclarations(method.ReturnTypeCustomAttributes) if method.ReturnTypeCustomAttributes
		Output.WriteLine(":")
		Indent++
		if bugged = method as CodeConstructor:
			if bugged.BaseConstructorArgs.IsValid():
				Output.Write("super(")
				OutputExpressionList(bugged.BaseConstructorArgs)
				Output.WriteLine(")")
			if bugged.ChainedConstructorArgs.IsValid():
				Output.Write("self(")
				OutputExpressionList(bugged.ChainedConstructorArgs)
				Output.WriteLine(")")
		GenerateStatements(method.Statements)
		passcheck(method.Statements)
		Indent--

	def MemberReference(target as CodeExpression, member as string):
		GenerateExpression(target)
		Output.Write(".${member}")

	def Indexer(target as CodeExpression, indices as CodeExpressionCollection):
		GenerateExpression(target)
		Output.Write("[")
		OutputExpressionList(indices)
		Output.Write("]")

	def Invocation(target as CodeExpression, parameters as CodeExpressionCollection):
		GenerateExpression(target)
		Output.Write("(")
		OutputExpressionList(parameters)
		Output.Write(")")

	def passcheck(stuff as ICollection):
		return if stuff.IsValid()
		Output.Write("pass")

	override def OutputTypeNamePair(type as CodeTypeReference, name as string):
		Output.Write("${name} as ")
		OutputType(type)

	protected override def GenerateParameterDeclarationExpression(e as CodeParameterDeclarationExpression):
		OutputAttributes(e.CustomAttributes, null, true);
		OutputDirection(e.Direction)
		OutputTypeNamePair(e.Type, e.Name)

	private def OutputAttributes(attributes as CodeAttributeDeclarationCollection, prefix as string, inline as bool):
		for att as CodeAttributeDeclaration in attributes:
			GenerateAttributeDeclarationsStart(attributes)
			Output.Write(prefix) if prefix
			OutputAttributeDeclaration(att)
			GenerateAttributeDeclarationsEnd(attributes)
			if inline:
				Output.Write(" ")
			else:
				Output.WriteLine()

	private def OutputAttributeDeclaration(attribute as CodeAttributeDeclaration):
		Output.Write(attribute.Name.Replace ('+', '.'))
		Output.Write('(')
		first = true
		for argument as CodeAttributeArgument in attribute.Arguments:
			if first:
				OutputAttributeArgument(argument)
				first = false
			else:
				Output.Write(", ")
				OutputAttributeArgument(argument)
		Output.Write(')')

	def ModifiersAndAttributes(typeMember as CodeTypeMember):
		OutputAttributeDeclarations(typeMember.CustomAttributes) if typeMember.CustomAttributes
		Output.WriteLine()
		to = { ziggy| return cast(int, ziggy) }
		fro = { ziggy| return cast(MemberAttributes, ziggy) }
		if typeMember.Attributes & MemberAttributes.VTableMask == MemberAttributes.New:
			typeMember.Attributes = fro(to(typeMember.Attributes) & ~ to(MemberAttributes.New))
		OutputMemberAccessModifier(typeMember.Attributes)
		OutputMemberScopeModifier(typeMember.Attributes)

	def OutputAttributeArgument(arg as CodeAttributeArgument):
		if arg.Name and arg.Name != "":
			Output.Write(arg.Name)
			Output.Write(" : ")
		GenerateExpression(arg.Value)

	protected override def OutputDirection(direction as FieldDirection):
		if direction == FieldDirection.Ref or direction == FieldDirection.Out:
			Output.Write("ref ")

	protected override def OutputFieldScopeModifier(attributes as MemberAttributes):
		scope = attributes & MemberAttributes.ScopeMask
		if scope == MemberAttributes.Static:
			Output.Write("static ")
		elif scope == MemberAttributes.Const:
			Output.Write("static final ")

	private def AsBool(data):
		return data is not null and data isa bool and cast(bool,data)

	protected override def GenerateCompileUnitStart(compileUnit as CodeCompileUnit):
		GenerateComment(CodeComment("------------------------------------------------------------------------------"))
		GenerateComment(CodeComment("This code was automatically generated by Boo.Lang.CodeDom v.${BooVersion}."))
		GenerateComment(CodeComment(""))
		GenerateComment(CodeComment("     Changes to this file may cause incorrect behavior and will be lost if "))
		GenerateComment(CodeComment("     the code is regenerated."))
		GenerateComment(CodeComment("------------------------------------------------------------------------------"))
		Output.WriteLine()

		//for future:
		//if AsBool(compileUnit.UserData["WhiteSpaceAgnostic"]):
		//	Output.WriteLine("Option WhiteSpaceAgnostic")

		super.GenerateCompileUnitStart(compileUnit)

	protected override def GenerateCompileUnit(compileUnit as CodeCompileUnit):
		GenerateCompileUnitStart(compileUnit)

		for ns as CodeNamespace in compileUnit.Namespaces:
			GenerateNamespace(ns)

		if compileUnit.AssemblyCustomAttributes.Count > 0:
			OutputAttributes(compileUnit.AssemblyCustomAttributes,
					"assembly:", false)
			Output.WriteLine("")

		GenerateCompileUnitEnd(compileUnit)

#region license
// Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//     * Neither the name of Rodrigo B. de Oliveira nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

// authors:
// Arron Washington
// Ian MacLean (original C# version)

//See also:
//http://svn.myrealbox.com/viewcvs/trunk/mcs/class/System/Microsoft.CSharp/CSharpCodeGenerator.cs?view=auto
//http://svn.myrealbox.com/viewcvs/trunk/mcs/class/System/Microsoft.VisualBasic/VBCodeGenerator.cs?view=auto

namespace Boo.Lang.CodeDom

import System
import System.CodeDom
import System.CodeDom.Compiler
import System.IO
import System.Reflection
import System.Collections
import System.Text.RegularExpressions

class BooCodeGenerator(CodeGenerator):
	static newlinePattern = Regex("\\n",RegexOptions.Compiled)

	static whiteSpacePattern = Regex("(\\s*)",RegexOptions.Compiled)

	static primitives = { "System.Double" : "double",
						"System.Single" : "single",
						"System.Int32" : "int",
						"System.Int64" : "long",
						"System.Int16" : "short",
						"System.UInt16" : "ushort",
						"System.Boolean" : "bool",
						"System.Char" : "char",
						"System.String" : "string",
						"System.Object" : "object",
						"System.Void" : "void"}

	protected NullToken as string:
		get:
			return "null"

	protected override def OutputType(typeRef as CodeTypeReference):
		Output.Write(GetTypeOutput(typeRef))

	protected override def GenerateArrayCreateExpression(exp as CodeArrayCreateExpression) :
		if exp.Initializers.Count:
			Output.Write("(")
			OutputExpressionList(exp.Initializers)
			Output.Write(")")
		else:
			Output.Write("array(")
			OutputType(exp.CreateType)
			Output.Write(",")
			if exp.SizeExpression:
				GenerateExpression(exp)
			else:
				Output.Write(exp.Size)
			Output.Write(")")

	protected override def GenerateBaseReferenceExpression(e as CodeBaseReferenceExpression) :
		Output.Write("super")

	protected override def GenerateCastExpression(e as CodeCastExpression) :
		Output.Write("cast(")
		OutputType(e.TargetType)
		Output.Write(",")
		GenerateExpression(e.Expression)
		Output.Write(")")

	protected override def GenerateDelegateCreateExpression(e as CodeDelegateCreateExpression) :
		GenerateExpression(e.TargetObject)
		Output.Write(".${e.MethodName} as ")
		OutputType(e.DelegateType)

	protected override def GenerateFieldReferenceExpression(e as CodeFieldReferenceExpression):
		MemberReference(e.TargetObject, e.FieldName)

	protected override def GenerateArgumentReferenceExpression(e as CodeArgumentReferenceExpression) :
		Output.Write(e.ParameterName)

	protected override def GenerateVariableReferenceExpression(e as CodeVariableReferenceExpression) :
		Output.Write(e.VariableName)

	protected override def GenerateIndexerExpression(e as CodeIndexerExpression) :
		Indexer(e.TargetObject, e.Indices)

	protected override def GenerateArrayIndexerExpression(e as CodeArrayIndexerExpression) :
		Indexer(e.TargetObject, e.Indices)

	protected override def GenerateMethodInvokeExpression(e as CodeMethodInvokeExpression) :
		Invocation(e.Method, e.Parameters)

	protected override def GenerateMethodReferenceExpression(e as CodeMethodReferenceExpression) :
		MemberReference(e.TargetObject, e.MethodName)
	protected override def GenerateEventReferenceExpression(e as CodeEventReferenceExpression) :
		MemberReference(e.TargetObject, e.EventName)

	protected override def GenerateDelegateInvokeExpression(e as CodeDelegateInvokeExpression) :
		Invocation(e.TargetObject, e.Parameters)

	protected override def GenerateObjectCreateExpression(e as CodeObjectCreateExpression) :
		OutputType(e.CreateType)
		Output.Write("(")
		OutputExpressionList(e.Parameters)
		Output.Write(")")

	protected override def GeneratePropertyReferenceExpression(e as CodePropertyReferenceExpression) :
		MemberReference(e.TargetObject, e.PropertyName)

	protected override def GeneratePropertySetValueReferenceExpression(e as CodePropertySetValueReferenceExpression) :
		Output.Write("value")

	protected override def GenerateThisReferenceExpression(e as CodeThisReferenceExpression) :
		Output.Write("self")

	protected override def GenerateExpressionStatement(e as CodeExpressionStatement) :
		GenerateExpression(e.Expression)
		Output.WriteLine();

	protected override def GenerateIterationStatement(e as CodeIterationStatement) :
		GenerateStatement(e.InitStatement)
		Output.Write("while ")
		GenerateExpression(e.TestExpression)
		Output.Write(":")
		Indent++
		GenerateStatements(e.Statements)
		GenerateStatement(e.IncrementStatement)
		Indent--

	protected override def GenerateThrowExceptionStatement(e as CodeThrowExceptionStatement) :
		Output.Write("raise ")
		GenerateExpression(e.ToThrow)

	protected override def GenerateComment(comment as CodeComment) :
		//TODO: check comment.DocComment when boo doc format is available
		commentSymbol = "#"
		txt = comment.Text

		Output.Write(commentSymbol + " ")

		i = 0
		while i<len(txt):
			rawArrayIndexing:
				Output.Write(txt[i])
				if txt[i] == char('\r'):
					if i<len(txt)-1 and txt[i+1]==char('\n'):
						continue
					Output.Write(commentSymbol)
				elif txt[i] == char('\n'):
					Output.Write(commentSymbol)
			++i
		Output.WriteLine()

	protected override def GenerateMethodReturnStatement(e as CodeMethodReturnStatement) :
		Output.Write("return ")
		GenerateExpression(e.Expression)
		Output.WriteLine()

	protected override def GenerateConditionStatement(e as CodeConditionStatement) :
		Output.Write("if ")
		GenerateExpression(e.Condition)
		Output.WriteLine(":")
		Indent++
		GenerateStatements(e.TrueStatements)
		Output.WriteLine ("pass") if len(e.TrueStatements) == 0
		Indent--
		return unless e.FalseStatements.IsValid()
		Output.WriteLine("else:")
		Indent++
		GenerateStatements(e.FalseStatements)
		Output.WriteLine ("pass") if len(e.TrueStatements) == 0
		Indent--

	protected override def GenerateTryCatchFinallyStatement(e as CodeTryCatchFinallyStatement) :
		Output.Write("try:")
		Indent++
		GenerateStatements(e.TryStatements)
		Indent--
		for exp as CodeCatchClause in e.CatchClauses:
			Output.Write("except ")
			Output.Write("${exp.LocalName} as ")
			OutputType(exp.CatchExceptionType)
			Output.Write(":")
			Indent++
			GenerateStatements(exp.Statements)
			Indent--
		GenerateStatements(e.FinallyStatements)

	protected override def GenerateAssignStatement(e as CodeAssignStatement) :
		GenerateExpression(e.Left)
		Output.Write(" = ")
		GenerateExpression(e.Right)
		Output.WriteLine()
	protected override def GenerateAttachEventStatement(e as CodeAttachEventStatement) :
		GenerateExpression(e.Event)
		Output.Write(" += ")
		GenerateExpression(e.Listener)
		Output.WriteLine()
	protected override def GenerateRemoveEventStatement(e as CodeRemoveEventStatement) :
		GenerateExpression(e.Event)
		Output.Write(" -= ")
		GenerateExpression(e.Listener)
		Output.WriteLine()
	protected override def GenerateGotoStatement(e as CodeGotoStatement) :
		Output.WriteLine("goto ${e.Label}")
	protected override def GenerateLabeledStatement(e as CodeLabeledStatement) :
		Output.WriteLine(":${e.Label}")
		GenerateStatement(e.Statement) if e.Statement
	protected override def GenerateVariableDeclarationStatement(e as CodeVariableDeclarationStatement) :
		Output.Write("${e.Name} as ")
		OutputType(e.Type)
		if e.InitExpression:
			Output.Write(" = ")
			GenerateExpression(e.InitExpression)
		Output.WriteLine()
	protected override def GenerateLinePragmaStart(e as CodeLinePragma) :
		pass

	protected override def GenerateLinePragmaEnd(e as CodeLinePragma) :
		pass

	protected override def GenerateEvent(e as CodeMemberEvent, c as CodeTypeDeclaration) :

		if e.PrivateImplementationType:
			raise "Does not support private implementation type."
		if e.ImplementationTypes.IsValid():
			raise "Does not implement these types: ${join(e.ImplementationTypes)}"
		e.Attributes |= MemberAttributes.Final

		ModifiersAndAttributes(e)

		Output.Write("event ${e.Name} as ")
		OutputType(e.Type)
		Output.WriteLine()
	protected override def GenerateField(e as CodeMemberField) :

		ModifiersAndAttributes(e)
		Output.Write("${e.Name} as ")
		OutputType(e.Type)
		if e.InitExpression:
			Output.Write(" = ")
			GenerateExpression(e.InitExpression)
		Output.WriteLine()

	protected override def GenerateSnippetMember(e as CodeSnippetTypeMember) :
		OutputAttributeDeclarations(e.CustomAttributes) if e.CustomAttributes
		Output.Write(FixIndent(e.Text))

	protected override def GenerateSnippetExpression(e as CodeSnippetExpression) :
		//Output.Write("("+e.Value+")")
		Output.Write(e.Value)

	protected override def GenerateSnippetCompileUnit(e as CodeSnippetCompileUnit) :
		Output.Write(FixIndent(e.Value))

	protected override def GenerateSnippetStatement(e as CodeSnippetStatement) :
		Output.Write(FixIndent(e.Value))

	protected def FixIndent(code as string) as string:
		return string.Empty if code is null or code==string.Empty

		spacespertab = 4
		indentspaces = " "*spacespertab

		code = code.Replace("\t",indentspaces)

		//find first line that has non-whitespace and isn't a comment
		lines = newlinePattern.Split(code.Replace("\r\n", "\n"))
		foundfirst = false  //1st non-whitespace, non-commented line
		insidecomment = 0
		for line in lines:
			trimmed = line.Trim()
			if trimmed == string.Empty:
				continue

			startmultiline = trimmed.StartsWith("/*")

			//if not whitespace and not a comment...
			if (insidecomment <= 0 and
					not startmultiline and
					not trimmed.StartsWith("#") and
					not trimmed.StartsWith("//")):
				foundfirst = true
				first = line
				break //stop for loop

			//special stuff for handling multiline comments
			if startmultiline or insidecomment > 0:
				j = 0
				linelen = len(trimmed) - 1
				while j < linelen:
					rawArrayIndexing:
						c = trimmed[j]
					if c==char('/'):
						rawArrayIndexing:
							nextc = trimmed[j+1]
						if nextc==char('*'):
							++insidecomment
							++j
					elif c==char('*') and insidecomment > 0:
						rawArrayIndexing:
							nextc = trimmed[j+1]
						if nextc==char('/'):
							--insidecomment
							++j
					++j

		if not foundfirst:  //all whitespace or comments
			return code

		indentprefix = string.Empty
		//how much the code should be indented:
		indentprefix = " " * (Indent * spacespertab) if Indent > 0

		//how much the code actually is indented:
		indent = whiteSpacePattern.Match(first).Groups[0].Value

		//if code is properly indented, return now
		return code if indent == indentprefix

		buffer = System.Text.StringBuilder()
		sz = len(indent)
		firstline = true
		for line in lines:
			if not firstline: //indentedtextwriter will handle indenting first line
				buffer.Append(indentprefix)
			else:
				firstline = false
			if sz==0 or not line.StartsWith(indent):
				buffer.Append(line)
			else:
				buffer.Append(line[sz:])
			buffer.Append("\n")
		return buffer.ToString()

	protected override def GenerateEntryPointMethod(e as CodeEntryPointMethod, c as CodeTypeDeclaration) :
		Method(e, "Main")

	protected override def GenerateMethod(e as CodeMemberMethod, c as CodeTypeDeclaration) :
		Method(e, e.Name)

	protected override def GenerateProperty(e as CodeMemberProperty, c as CodeTypeDeclaration) :
		ModifiersAndAttributes(e)

		Output.Write(" ${e.Name} ")
		if len(e.Parameters) > 1:
			Output.Write("(")
			OutputParameters(e.Parameters)
			Output.Write(")")
		Output.Write(" as ")
		OutputType(e.Type)
		Output.WriteLine(":")
		Indent++
		if e.HasGet:
			Output.WriteLine("get:")
			Indent++
			GenerateStatements(e.GetStatements)
			passcheck(e.GetStatements)
			Indent--
			Output.WriteLine()
		if e.HasSet:
			Output.WriteLine("set:")
			Indent++
			GenerateStatements(e.SetStatements)
			passcheck(e.SetStatements)
			Indent--
			Output.WriteLine()
		Indent--
		Output.WriteLine()
	protected override def GenerateConstructor(e as CodeConstructor, c as CodeTypeDeclaration) :
		Method(e, "constructor")

	protected override def GenerateTypeConstructor(e as CodeTypeConstructor) :
		e.Attributes |= MemberAttributes.Static
		e.Parameters.Clear()
		Method(e, "constructor")

	protected override def GenerateTypeStart(e as CodeTypeDeclaration):
		Output.WriteLine()
		OutputAttributeDeclarations(e.CustomAttributes)
		Output.WriteLine()
		if e.TypeAttributes & TypeAttributes.Sealed:
			e.TypeAttributes = (e.TypeAttributes.ToInt() & ~TypeAttributes.Sealed.ToInt()).ToEnum(TypeAttributes)
			Output.Write("final ")
		if e isa CodeTypeDelegate:
			GenerateDelegate(e)
			return
		OutputTypeAttributes(e.TypeAttributes, e.IsStruct, e.IsEnum)
		Output.Write(" ${e.Name}(")
		for index in range(len(e.BaseTypes)):
			var as CodeTypeReference = e.BaseTypes[index]
			OutputType(var)
			continue unless index + 1 != e.BaseTypes.Count
			Output.Write(",")
		Output.Write("):")
		Indent++
		#Ah hah hah, yeah, no. Empty class.
		passcheck(e.Members)

	private def GenerateDelegate(e as CodeTypeDelegate):
		if e.TypeAttributes & TypeAttributes.NestedFamORAssem == TypeAttributes.Public:
			Output.Write("public ")
		Output.Write("callable ${e.Name}(")
		OutputParameters(e.Parameters)
		Output.Write(") as ")
		OutputType(e.ReturnType)

	protected override def GenerateTypeEnd(e as CodeTypeDeclaration) :
		Indent--

	protected override def GenerateNamespaceStart(e as CodeNamespace) :
		Output.WriteLine("namespace ${e.Name}")

	protected override def GenerateNamespaceEnd(e as CodeNamespace) :
		pass

	protected override def GenerateNamespaceImport(e as CodeNamespaceImport) :
		Output.WriteLine("import ${e.Namespace}")

	protected override def GenerateAttributeDeclarationsStart(attributes as CodeAttributeDeclarationCollection) :
		Output.Write("[")

	protected override def GenerateAttributeDeclarationsEnd(attributes as CodeAttributeDeclarationCollection) :
		Output.Write("]")

	protected override def Supports(support as GeneratorSupport) as bool:
		return true

	protected override def IsValidIdentifier(value as string) as bool:
		return true

	protected override def CreateEscapedIdentifier(value as string) as string:
		return value

	protected override def CreateValidIdentifier(value as string) as string:
		return value

	protected override def GetTypeOutput(typeRef as CodeTypeReference):
		if typeRef.ArrayElementType:
			out = GetTypeOutput(typeRef.ArrayElementType)
		elif typeRef.BaseType in primitives:
			out = primitives[typeRef.BaseType]
		else:
			out = typeRef.BaseType

		if typeRef.ArrayRank > 0:
			if typeRef.ArrayRank > 1:
				return "(${out}, ${typeRef.ArrayRank})"
			return "(${out})"
		return out

	protected override def QuoteSnippetString(snippet as string) as string:
		s = snippet.Replace("\\", "\\\\")
		s = s.Replace("\"", "\\\"")
		s = s.Replace("\t", "\\t")
		s = s.Replace("\r", "\\r")
		s = s.Replace("\n", "\\n")
		return "\"" + s + "\""

	def Method(method as duck, name as string):
		ModifiersAndAttributes(method)
		Output.Write("def ${name} (")
		OutputParameters(method.Parameters)
		Output.Write(")")
		unless GetTypeOutput(method.ReturnType) == "void":
			Output.Write(" as ")
			OutputType(method.ReturnType)
			OutputAttributeDeclarations(method.ReturnTypeCustomAttributes) if method.ReturnTypeCustomAttributes
		Output.WriteLine(":")
		Indent++
		if bugged = method as CodeConstructor:
			if bugged.BaseConstructorArgs.IsValid():
				Output.Write("super(")
				OutputExpressionList(bugged.BaseConstructorArgs)
				Output.WriteLine(")")
			if bugged.ChainedConstructorArgs.IsValid():
				Output.Write("self(")
				OutputExpressionList(bugged.ChainedConstructorArgs)
				Output.WriteLine(")")
		GenerateStatements(method.Statements)
		passcheck(method.Statements)
		Indent--

	def MemberReference(target as CodeExpression, member as string):
		GenerateExpression(target)
		Output.Write(".${member}")

	def Indexer(target as CodeExpression, indices as CodeExpressionCollection):
		GenerateExpression(target)
		Output.Write("[")
		OutputExpressionList(indices)
		Output.Write("]")

	def Invocation(target as CodeExpression, parameters as CodeExpressionCollection):
		GenerateExpression(target)
		Output.Write("(")
		OutputExpressionList(parameters)
		Output.Write(")")

	def passcheck(stuff as ICollection):
		return if stuff.IsValid()
		Output.Write("pass")

	override def OutputTypeNamePair(type as CodeTypeReference, name as string):
		Output.Write("${name} as ")
		OutputType(type)

	protected override def GenerateParameterDeclarationExpression(e as CodeParameterDeclarationExpression):
		OutputAttributes(e.CustomAttributes, null, true);
		OutputDirection(e.Direction)
		OutputTypeNamePair(e.Type, e.Name)

	private def OutputAttributes(attributes as CodeAttributeDeclarationCollection, prefix as string, inline as bool):
		for att as CodeAttributeDeclaration in attributes:
			GenerateAttributeDeclarationsStart(attributes)
			Output.Write(prefix) if prefix
			OutputAttributeDeclaration(att)
			GenerateAttributeDeclarationsEnd(attributes)
			if inline:
				Output.Write(" ")
			else:
				Output.WriteLine()

	private def OutputAttributeDeclaration(attribute as CodeAttributeDeclaration):
		Output.Write(attribute.Name.Replace ('+', '.'))
		Output.Write('(')
		first = true
		for argument as CodeAttributeArgument in attribute.Arguments:
			if first:
				OutputAttributeArgument(argument)
				first = false
			else:
				Output.Write(", ")
				OutputAttributeArgument(argument)
		Output.Write(')')

	def ModifiersAndAttributes(typeMember as CodeTypeMember):
		OutputAttributeDeclarations(typeMember.CustomAttributes) if typeMember.CustomAttributes
		Output.WriteLine()
		to = { ziggy| return cast(int, ziggy) }
		fro = { ziggy| return cast(MemberAttributes, ziggy) }
		if typeMember.Attributes & MemberAttributes.VTableMask == MemberAttributes.New:
			typeMember.Attributes = fro(to(typeMember.Attributes) & ~ to(MemberAttributes.New))
		OutputMemberAccessModifier(typeMember.Attributes)
		OutputMemberScopeModifier(typeMember.Attributes)

	def OutputAttributeArgument(arg as CodeAttributeArgument):
		if arg.Name and arg.Name != "":
			Output.Write(arg.Name)
			Output.Write(" : ")
		GenerateExpression(arg.Value)

	protected override def OutputDirection(direction as FieldDirection):
		if direction == FieldDirection.Ref or direction == FieldDirection.Out:
			Output.Write("ref ")

	protected override def OutputFieldScopeModifier(attributes as MemberAttributes):
		scope = attributes & MemberAttributes.ScopeMask
		if scope == MemberAttributes.Static:
			Output.Write("static ")
		elif scope == MemberAttributes.Const:
			Output.Write("static final ")

	private def AsBool(data):
		return data is not null and data isa bool and cast(bool,data)

	protected override def GenerateCompileUnitStart(compileUnit as CodeCompileUnit):
		GenerateComment(CodeComment("------------------------------------------------------------------------------"))
		GenerateComment(CodeComment("This code was automatically generated by Boo.Lang.CodeDom v.${BooVersion}."))
		GenerateComment(CodeComment(""))
		GenerateComment(CodeComment("     Changes to this file may cause incorrect behavior and will be lost if "))
		GenerateComment(CodeComment("     the code is regenerated."))
		GenerateComment(CodeComment("------------------------------------------------------------------------------"))
		Output.WriteLine()

		//for future:
		//if AsBool(compileUnit.UserData["WhiteSpaceAgnostic"]):
		//	Output.WriteLine("Option WhiteSpaceAgnostic")

		super.GenerateCompileUnitStart(compileUnit)

	protected override def GenerateCompileUnit(compileUnit as CodeCompileUnit):
		GenerateCompileUnitStart(compileUnit)

		for ns as CodeNamespace in compileUnit.Namespaces:
			GenerateNamespace(ns)

		if compileUnit.AssemblyCustomAttributes.Count > 0:
			OutputAttributes(compileUnit.AssemblyCustomAttributes,
					"assembly:", false)
			Output.WriteLine("")

		GenerateCompileUnitEnd(compileUnit)


dont rely on CompilerParameter.EnableTraceSwitch

namespace boojay

import System
import System.Reflection
import System.Diagnostics
import System.IO as SysIO
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boojay.Compilation from Boojay.Compilation
import Boojay.Compilation.TypeSystem from Boojay.Compilation

import java.io
import java.util.zip

def loadAssembly(name as string):
	if SysIO.File.Exists(name):
		return Assembly.LoadFrom(name)
	return Assembly.Load(name)

def loadJar(name as string):
	return JarTypeSystemProvider().ForJar(name) if SysIO.File.Exists(name)
	raise Exception("Can' load library ${name}")

def parseCommandLine(argv as (string)):
	try:
		cmdLine = CommandLine(argv)
		if (not cmdLine.IsValid) or cmdLine.DoHelp:
			cmdLine.PrintOptions()
			return null
		return cmdLine
	except x:
		print "BCE000: ", x.Message
		return null

def selectPipeline(cmdLine as CommandLine):
	return (BoojayPipelines.ProduceBoo() if cmdLine.Boo else BoojayPipelines.ProduceBytecode())

def configureParams(cmdLine as CommandLine, params as CompilerParameters):
	for fname in cmdLine.SourceFiles():
		if cmdLine.Verbose: print fname
		params.Input.Add(FileInput(fname))

	for reference in dotNetReferences(cmdLine.References):
		params.References.Add(loadAssembly(reference))
	for classpath in retrieveJars(cmdLine.Classpaths):
		params.References.Add(loadJar(classpath))
	for classpath in jarReferences(cmdLine.References):
		params.References.Add(loadJar(classpath))

	params.OutputAssembly = getOutputDirectory(cmdLine)
	if cmdLine.DebugCompiler:
		params.TraceLevel = System.Diagnostics.TraceLevel.Verbose
		Trace.Listeners.Add(TextWriterTraceListener(System.Console.Error))

def dotNetReferences(references as List[of string]):
	return [reference for reference in references if (reference.EndsWith(".exe") or reference.EndsWith(".dll"))]

def jarReferences(references as List[of string]):
	for reference in references:
		yield reference if reference.EndsWith(".jar")

def retrieveJars(classpaths as List[of string]):
	for classpath in classpaths:
		if classpath.EndsWith(".jar"):
			yield classpath
		else:
			if SysIO.Directory.Exists(classpath):
				for jar in SysIO.Directory.GetFiles(classpath, "*.jar"):
					yield SysIO.Path.Combine(classpath, jar)
			else:
				print "Can' locate classpath: ${classpath}"

def showErrorsWarnings(cmdLine as CommandLine, result as CompilerContext):
	for error in result.Errors:
		print error.ToString(cmdLine.Verbose)
	for warning in result.Warnings:
		print warning

def outputJarFile(cmdLine as CommandLine, temporaryDirectory as string, result as CompilerContext):
	if result.Errors.Count == 0 and isJar(cmdLine.OutputDirectory):
		generateJar(cmdLine.OutputDirectory, temporaryDirectory, result["GeneratedClassFiles"])

def getOutputDirectory(cmdLine as CommandLine):
	return (SysIO.Path.GetTempPath() if isJar(cmdLine.OutputDirectory) else cmdLine.OutputDirectory)

def isJar(path as string):
	return path.EndsWith(".jar")

def generateJar(outputJar as string, temporaryDir as string, files as List):
	return unless files
	manifest = createManifest(temporaryDir)

	zos = ZipOutputStream(fos = FileOutputStream(outputJar))

	for name as string in files + [manifest]:
		zos.putNextEntry(ZipEntry(name.RemoveStart(temporaryDir)))
		zos.write(System.IO.File.ReadAllBytes(name))
		zos.closeEntry()

	zos.close()
	fos.close()

def createManifest(baseDir as string):
	filename = SysIO.Path.Combine(baseDir, "META-INF/MANIFEST.MF")
	SysIO.Directory.CreateDirectory(SysIO.Path.GetDirectoryName(filename))
	using file = SysIO.File.CreateText(filename):
		file.WriteLine("Manifest-Version: 1.0")
	return filename

[extension]
def RemoveStart(value as string, start as string):
	return value unless value.StartsWith(start)
	return value[start.Length:]

print "boojay .0a"

cmdLine = parseCommandLine(argv)
if cmdLine is null: return

compiler = newBoojayCompiler(selectPipeline(cmdLine))
configureParams(cmdLine, compiler.Parameters)

result = compiler.Run()

showErrorsWarnings(cmdLine, result)
outputJarFile(cmdLine, compiler.Parameters.OutputAssembly, result)

namespace boojay

import System
import System.Reflection
import System.Diagnostics
import System.IO as SysIO
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boojay.Compilation from Boojay.Compilation
import Boojay.Compilation.TypeSystem from Boojay.Compilation

import java.io
import java.util.zip

def loadAssembly(name as string):
	if SysIO.File.Exists(name):
		return Assembly.LoadFrom(name)
	return Assembly.Load(name)

def loadJar(name as string):
	return JarTypeSystemProvider().ForJar(name) if SysIO.File.Exists(name)
	raise Exception("Can' load library ${name}")

def parseCommandLine(argv as (string)):
	try:
		cmdLine = CommandLine(argv)
		if (not cmdLine.IsValid) or cmdLine.DoHelp:
			cmdLine.PrintOptions()
			return null
		return cmdLine
	except x:
		print "BCE000: ", x.Message
		return null

def selectPipeline(cmdLine as CommandLine):
	return (BoojayPipelines.ProduceBoo() if cmdLine.Boo else BoojayPipelines.ProduceBytecode())

def configureParams(cmdLine as CommandLine, params as CompilerParameters):
	for fname in cmdLine.SourceFiles():
		if cmdLine.Verbose: print fname
		params.Input.Add(FileInput(fname))

	for reference in dotNetReferences(cmdLine.References):
		params.References.Add(loadAssembly(reference))
	for classpath in retrieveJars(cmdLine.Classpaths):
		params.References.Add(loadJar(classpath))
	for classpath in jarReferences(cmdLine.References):
		params.References.Add(loadJar(classpath))

	params.OutputAssembly = getOutputDirectory(cmdLine)
	if cmdLine.DebugCompiler:
		params.EnableTraceSwitch()
		params.TraceLevel = System.Diagnostics.TraceLevel.Verbose
		Trace.Listeners.Add(TextWriterTraceListener(System.Console.Error))

def dotNetReferences(references as List[of string]):
	return [reference for reference in references if (reference.EndsWith(".exe") or reference.EndsWith(".dll"))]

def jarReferences(references as List[of string]):
	for reference in references:
		yield reference if reference.EndsWith(".jar")

def retrieveJars(classpaths as List[of string]):
	for classpath in classpaths:
		if classpath.EndsWith(".jar"):
			yield classpath
		else:
			if SysIO.Directory.Exists(classpath):
				for jar in SysIO.Directory.GetFiles(classpath, "*.jar"):
					yield SysIO.Path.Combine(classpath, jar)
			else:
				print "Can' locate classpath: ${classpath}"

def showErrorsWarnings(cmdLine as CommandLine, result as CompilerContext):
	for error in result.Errors:
		print error.ToString(cmdLine.Verbose)
	for warning in result.Warnings:
		print warning

def outputJarFile(cmdLine as CommandLine, temporaryDirectory as string, result as CompilerContext):
	if result.Errors.Count == 0 and isJar(cmdLine.OutputDirectory):
		generateJar(cmdLine.OutputDirectory, temporaryDirectory, result["GeneratedClassFiles"])

def getOutputDirectory(cmdLine as CommandLine):
	return (SysIO.Path.GetTempPath() if isJar(cmdLine.OutputDirectory) else cmdLine.OutputDirectory)

def isJar(path as string):
	return path.EndsWith(".jar")

def generateJar(outputJar as string, temporaryDir as string, files as List):
	return unless files
	manifest = createManifest(temporaryDir)

	zos = ZipOutputStream(fos = FileOutputStream(outputJar))

	for name as string in files + [manifest]:
		zos.putNextEntry(ZipEntry(name.RemoveStart(temporaryDir)))
		zos.write(System.IO.File.ReadAllBytes(name))
		zos.closeEntry()

	zos.close()
	fos.close()

def createManifest(baseDir as string):
	filename = SysIO.Path.Combine(baseDir, "META-INF/MANIFEST.MF")
	SysIO.Directory.CreateDirectory(SysIO.Path.GetDirectoryName(filename))
	using file = SysIO.File.CreateText(filename):
		file.WriteLine("Manifest-Version: 1.0")
	return filename

[extension]
def RemoveStart(value as string, start as string):
	return value unless value.StartsWith(start)
	return value[start.Length:]

print "boojay .0a"

cmdLine = parseCommandLine(argv)
if cmdLine is null: return

compiler = newBoojayCompiler(selectPipeline(cmdLine))
configureParams(cmdLine, compiler.Parameters)

result = compiler.Run()

showErrorsWarnings(cmdLine, result)
outputJarFile(cmdLine, compiler.Parameters.OutputAssembly, result)


BooBinding: Fixed bugs in BooAmbience.

BooBinding: Fixed bugs in BooAmbience.

git-svn-id: c3b8989232654601f1acea7403f771adaaa44a81@1347 2c1201b4-01cd-e047-a400-b836ae1fbc61

namespace BooBinding

import System
import System.Collections
import System.Text
import SharpDevelop.Internal.Parser
import ICSharpCode.SharpDevelop.Services
import ICSharpCode.Core.Properties
import ICSharpCode.Core.Services

class BooAmbience(AbstractAmbience):
	[Getter(TypeConversionTable)]
	static _typeConversionTable = {
		'System.Void'    : 'void',
		'System.Object'  : 'object',
		'System.Boolean' : 'bool',
		'System.Byte'    : 'byte',
		//'System.SByte' : 'sbyte',
		//'System.Char' : 'char',
		//'System.Enum' : 'enum',
		'System.Int16'  : 'short',
		'System.Int32'  : 'int',
		'System.Int64'  : 'long',
		'System.UInt16' : 'ushort',
		'System.UInt32' : 'uint',
		'System.UInt64' : 'ulong',
		'System.Single' : 'single',
		'System.Double' : 'double',
		// 'System.Decimal' : 'decimal',
		'System.String' : 'string',
		'System.DateTime' : 'date',
		'System.Type'  : 'type',
		'System.Array' : 'array',
		'System.Text.RegularExpressions.Regex' : 'regex'
		}

	private def ModifierIsSet(modifier as ModifierEnum, query as ModifierEnum) as bool:
		return (modifier & query) == query

	override def Convert(modifier as ModifierEnum) as string:
		if ShowAccessibility:
			if ModifierIsSet(modifier, ModifierEnum.Public):
				return 'public '
			elif ModifierIsSet(modifier, ModifierEnum.Private):
				return 'private '
			elif ModifierIsSet(modifier, ModifierEnum.ProtectedAndInternal):
				return 'protected internal '
			elif ModifierIsSet(modifier, ModifierEnum.ProtectedOrInternal):
				return 'internal protected '
			elif ModifierIsSet(modifier, ModifierEnum.Internal):
				return 'internal '
			elif ModifierIsSet(modifier, ModifierEnum.Protected):
				return 'protected '
		return ''

	private def GetModifier(decoration as IDecoration) as string:
		ret as string = ''
		if IncludeHTMLMarkup:
			ret += ''

		if decoration.IsStatic:
			ret += 'static '
		elif decoration.IsFinal:
			ret += 'final '
		elif decoration.IsVirtual:
			ret += 'virtual '
		elif decoration.IsOverride:
			ret += 'override '
		elif decoration.IsNew:
			ret += 'new '

		if IncludeHTMLMarkup:
			ret += ''

		return ret

	override def Convert(c as IClass) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(c.Modifiers))
		if IncludeHTMLMarkup:
			builder.Append('')

		cType = c.ClassType

		if ShowModifiers:
			if c.IsSealed:
				if cType == ClassType.Delegate or cType == ClassType.Enum:
					pass
				else:
					builder.Append('final ')
			elif c.IsAbstract and cType != ClassType.Interface:
				builder.Append('abstract ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if ShowModifiers:
			if cType == ClassType.Delegate:
				builder.Append('callable ')
			elif cType == ClassType.Class:
				builder.Append('class ')
			elif cType == ClassType.Struct:
				builder.Append('struct ')
			elif cType == ClassType.Interface:
				builder.Append('interface ')
			elif cType == ClassType.Enum:
				builder.Append('enum ')

		if cType == ClassType.Delegate and c.Methods.Count > 0:
			for m as IMethod in c.Methods:
				if m.Name == 'Invoke':
					builder.Append(Convert(m.ReturnType))
					builder.Append(' ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if UseFullyQualifiedMemberNames:
			builder.Append(c.FullyQualifiedName)
		else:
			builder.Append(c.Name)

		if IncludeHTMLMarkup:
			builder.Append('')

		if c.ClassType == ClassType.Delegate:
			builder.Append(' (')
			if IncludeHTMLMarkup:
				builder.Append('
')

			for m as IMethod in c.Methods:
				if m.Name == 'Invoke':
					for i in range(m.Parameters.Count):
						if IncludeHTMLMarkup:
							builder.Append('   ')

						builder.Append(Convert(m.Parameters[i]))
						if i + 1 < m.Parameters.Count:
							builder.Append(', ')

						if IncludeHTMLMarkup:
							builder.Append('
')

			builder.Append(Char.Parse(')'))
		elif ShowInheritanceList:
			if c.BaseTypes.Count > 0:
				builder.Append('(')
				for i in range(c.BaseTypes.Count):
					builder.Append(c.BaseTypes[i])
					if i + 1 < c.BaseTypes.Count:
						builder.Append(', ')
				builder.Append(')')

		if IncludeBodies:
			builder.Append(':\n')

		return builder.ToString()

	override def ConvertEnd(c as IClass) as string:
		return ''

	override def Convert(field as IField) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(field.Modifiers))
		if IncludeHTMLMarkup:
			builder.Append('')

		if ShowModifiers:
			if field.IsStatic and field.IsLiteral:
				builder.Append('const ')
			elif field.IsStatic:
				builder.Append('static ')

			if field.IsReadonly:
				builder.Append('readonly ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if IncludeHTMLMarkup:
			builder.Append('')

		if UseFullyQualifiedMemberNames:
			builder.Append(field.FullyQualifiedName)
		else:
			builder.Append(field.Name)

		if field.ReturnType != null and ShowReturnType:
			builder.Append(' as ')
			builder.Append(Convert(field.ReturnType))

		if IncludeHTMLMarkup:
			builder.Append('')

		return builder.ToString()

	override def Convert(property as IProperty) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(property.Modifiers))
		if ShowModifiers:
			builder.Append(GetModifier(property))

		if IncludeHTMLMarkup:
			builder.Append('')

		if UseFullyQualifiedMemberNames:
			builder.Append(property.FullyQualifiedName)
		else:
			builder.Append(property.Name)

		if IncludeHTMLMarkup:
			builder.Append('')

		if property.Parameters.Count > 0:
			builder.Append('(')
			if IncludeHTMLMarkup:
				builder.Append('
')

			for i in range(property.Parameters.Count):
				if IncludeHTMLMarkup:
					builder.Append('   ')

				builder.Append(Convert(property.Parameters[i]))
				if i + 1 < property.Parameters.Count:
					builder.Append(', ')

				if IncludeHTMLMarkup:
					builder.Append('
')

			builder.Append(')')

		if property.ReturnType != null and ShowReturnType:
			builder.Append(' as ')
			builder.Append(Convert(property.ReturnType))

		if IncludeBodies:
			builder.Append(': ')
			if property.CanGet:
				builder.Append('get ')

			if property.CanSet:
				builder.Append('set ')

		return builder.ToString()

	override def Convert(e as IEvent) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(e.Modifiers))
		if ShowModifiers:
			builder.Append(GetModifier(e))

		if IncludeHTMLMarkup:
			builder.Append('')

		if UseFullyQualifiedMemberNames:
			builder.Append(e.FullyQualifiedName)
		else:
			builder.Append(e.Name)

		if IncludeHTMLMarkup:
			builder.Append('')

		if e.ReturnType != null and ShowReturnType:
			builder.Append(' as ')
			builder.Append(Convert(e.ReturnType))

		return builder.ToString()

	override def Convert(m as IIndexer) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(m.Modifiers))
		if IncludeHTMLMarkup:
			builder.Append('')

		if ShowModifiers and m.IsStatic:
			builder.Append('static ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if m.ReturnType != null and ShowReturnType:
			builder.Append(Convert(m.ReturnType))
			builder.Append(' ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if UseFullyQualifiedMemberNames:
			builder.Append(m.FullyQualifiedName)
		else:
			builder.Append(m.Name)

		if IncludeHTMLMarkup:
			builder.Append('')

		builder.Append('Indexer(')
		if IncludeHTMLMarkup:
			builder.Append('
')

		for i in range(m.Parameters.Count):
			if IncludeHTMLMarkup:
				builder.Append('   ')

			builder.Append(Convert(m.Parameters[i]))
			if i + 1 < m.Parameters.Count:
				builder.Append(', ')

			if IncludeHTMLMarkup:
				builder.Append('
')

		builder.Append(')')

		return builder.ToString()

	override def Convert(m as IMethod) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(m.Modifiers))
		if ShowModifiers:
			builder.Append(GetModifier(m))

		builder.Append('def ') if ShowReturnType

		if IncludeHTMLMarkup:
			builder.Append('')

		if m.IsConstructor:
			builder.Append('constructor')
		else:
			if UseFullyQualifiedMemberNames:
				builder.Append(m.FullyQualifiedName)
			else:
				builder.Append(m.Name)

		if IncludeHTMLMarkup:
			builder.Append('')

		builder.Append('(')
		if IncludeHTMLMarkup:
			builder.Append('
')

		for i in range(m.Parameters.Count):
			if IncludeHTMLMarkup:
				builder.Append('   ')

			builder.Append(Convert(m.Parameters[i]))
			if i + 1 < m.Parameters.Count:
				builder.Append(', ')

			if IncludeHTMLMarkup:
				builder.Append('
')

		builder.Append(')')

		if m.ReturnType != null and ShowReturnType and not m.IsConstructor:
			builder.Append(' as ')
			builder.Append(Convert(m.ReturnType))

		if IncludeBodies:
			if m.DeclaringType != null:
				if m.DeclaringType.ClassType != ClassType.Interface:
					builder.Append(': ')
			else:
				builder.Append(': ')

		return builder.ToString()

	override def ConvertEnd(m as IMethod) as string:
		return ''

	override def Convert(returnType as IReturnType) as string:
		if returnType == null:
			return ''

		builder as StringBuilder = StringBuilder()
		/*
		linkSet as bool = false
		if UseLinkArrayList:
			ret as SharpAssemblyReturnType = returnType as SharpAssemblyReturnType
			if ret != null:
				if ret.UnderlyingClass != null:
					builder.Append('')
					linkSet = true
		*/

		for i in range(returnType.ArrayCount):
			builder.Append('(')

		if returnType.FullyQualifiedName != null and _typeConversionTable[returnType.FullyQualifiedName] != null:
			builder.Append(_typeConversionTable[returnType.FullyQualifiedName])
		else:
			if UseFullyQualifiedNames:
				builder.Append(returnType.FullyQualifiedName)
			else:
				builder.Append(returnType.Name)

		//if linkSet:
		//	builder.Append('')

		if returnType.PointerNestingLevel > 0:
			// Sometimes there are negative pointer nesting levels
			// (especially in exception constructors in the BCL
			for i in range(returnType.PointerNestingLevel):
				builder.Append('*')

		for i in range(returnType.ArrayCount):
			if returnType.ArrayDimensions[i] > 1:
				builder.Append(',')
				builder.Append(returnType.ArrayDimensions[i])
			builder.Append(')')

		return builder.ToString()

	override def Convert(param as IParameter) as string:
		builder as StringBuilder = StringBuilder()
		if IncludeHTMLMarkup:
			builder.Append('')

		if param.IsRef:
			builder.Append('ref ')
		elif param.IsOut:
			builder.Append('out ')
		elif param.IsParams:
			builder.Append('params ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if ShowParameterNames:
			builder.Append(param.Name)
			builder.Append(' as ')
		builder.Append(Convert(param.ReturnType))

		return builder.ToString()

	override def WrapAttribute(attribute as string) as string:
		return '[' + attribute + ']'

	override def WrapComment(comment as string) as string:
		return '// ' + comment

	override def GetIntrinsicTypeName(dotNetTypeName as string) as string:
		if _typeConversionTable[dotNetTypeName] != null:
			return _typeConversionTable[dotNetTypeName]
		return dotNetTypeName

namespace BooBinding

import System
import System.Collections
import System.Text
import SharpDevelop.Internal.Parser
import ICSharpCode.SharpDevelop.Services
import ICSharpCode.Core.Properties
import ICSharpCode.Core.Services

class BooAmbience(AbstractAmbience):
	[Getter(TypeConversionTable)]
	static _typeConversionTable = {
		'System.Void'    : 'void',
		'System.Object'  : 'object',
		'System.Boolean' : 'bool',
		'System.Byte'    : 'byte',
		//'System.SByte' : 'sbyte',
		//'System.Char' : 'char',
		//'System.Enum' : 'enum',
		'System.Int16'  : 'short',
		'System.Int32'  : 'int',
		'System.Int64'  : 'long',
		'System.UInt16' : 'ushort',
		'System.UInt32' : 'uint',
		'System.UInt64' : 'ulong',
		'System.Single' : 'single',
		'System.Double' : 'double',
		// 'System.Decimal' : 'decimal',
		'System.String' : 'string',
		'System.DateTime' : 'date',
		'System.Type'  : 'type',
		'System.Array' : 'array',
		'System.Text.RegularExpressions.Regex' : 'regex'
		}

	private def ModifierIsSet(modifier as ModifierEnum, query as ModifierEnum) as bool:
		return (modifier & query) == query

	override def Convert(modifier as ModifierEnum) as string:
		if ShowAccessibility:
			if ModifierIsSet(modifier, ModifierEnum.Public):
				return 'public '
			elif ModifierIsSet(modifier, ModifierEnum.Private):
				return 'private '
			elif ModifierIsSet(modifier, ModifierEnum.ProtectedAndInternal):
				return 'protected internal '
			elif ModifierIsSet(modifier, ModifierEnum.ProtectedOrInternal):
				return 'internal protected '
			elif ModifierIsSet(modifier, ModifierEnum.Internal):
				return 'internal '
			elif ModifierIsSet(modifier, ModifierEnum.Protected):
				return 'protected '
		return ''

	private def GetModifier(decoration as IDecoration) as string:
		ret as string = ''
		if IncludeHTMLMarkup:
			ret += ''

		if decoration.IsStatic:
			ret += 'static '
		elif decoration.IsFinal:
			ret += 'final '
		elif decoration.IsVirtual:
			ret += 'virtual '
		elif decoration.IsOverride:
			ret += 'override '
		elif decoration.IsNew:
			ret += 'new '

		if IncludeHTMLMarkup:
			ret += ''

		return ret

	override def Convert(c as IClass) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(c.Modifiers))
		if IncludeHTMLMarkup:
			builder.Append('')

		cType = c.ClassType

		if ShowModifiers:
			if c.IsSealed:
				if cType == ClassType.Delegate or cType == ClassType.Enum:
					pass
				else:
					builder.Append('final ')
			elif c.IsAbstract and cType != ClassType.Interface:
				builder.Append('abstract ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if ShowModifiers:
			if cType == ClassType.Delegate:
				builder.Append('callable ')
			elif cType == ClassType.Class:
				builder.Append('class ')
			elif cType == ClassType.Struct:
				builder.Append('struct ')
			elif cType == ClassType.Interface:
				builder.Append('interface ')
			elif cType == ClassType.Enum:
				builder.Append('enum ')

		if cType == ClassType.Delegate and c.Methods.Count > 0:
			for m as IMethod in c.Methods:
				if m.Name == 'Invoke':
					builder.Append(Convert(m.ReturnType))
					builder.Append(' ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if UseFullyQualifiedMemberNames:
			builder.Append(c.FullyQualifiedName)
		else:
			builder.Append(c.Name)

		if IncludeHTMLMarkup:
			builder.Append('')

		if c.ClassType == ClassType.Delegate:
			builder.Append(' (')
			if IncludeHTMLMarkup:
				builder.Append('
')

			for m as IMethod in c.Methods:
				if m.Name == 'Invoke':
					for i in range(m.Parameters.Count):
						if IncludeHTMLMarkup:
							builder.Append('   ')

						builder.Append(Convert(m.Parameters[i]))
						if i + 1 < m.Parameters.Count:
							builder.Append(', ')

						if IncludeHTMLMarkup:
							builder.Append('
')

			builder.Append(Char.Parse(')'))
		elif ShowInheritanceList:
			if c.BaseTypes.Count > 0:
				builder.Append('(')
				for i in range(c.BaseTypes.Count):
					builder.Append(c.BaseTypes[i])
					if i + 1 < c.BaseTypes.Count:
						builder.Append(', ')
				builder.Append(')')

		if IncludeBodies:
			builder.Append(':\n')

		return builder.ToString()

	override def ConvertEnd(c as IClass) as string:
		return ''

	override def Convert(field as IField) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(field.Modifiers))
		if IncludeHTMLMarkup:
			builder.Append('')

		if ShowModifiers:
			if field.IsStatic and field.IsLiteral:
				builder.Append('const ')
			elif field.IsStatic:
				builder.Append('static ')

			if field.IsReadonly:
				builder.Append('readonly ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if IncludeHTMLMarkup:
			builder.Append('')

		if UseFullyQualifiedMemberNames:
			builder.Append(field.FullyQualifiedName)
		else:
			builder.Append(field.Name)

		if field.ReturnType != null and ShowReturnType:
			builder.Append(' as ')
			builder.Append(Convert(field.ReturnType))

		if IncludeHTMLMarkup:
			builder.Append('')

		return builder.ToString()

	override def Convert(property as IProperty) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(property.Modifiers))
		if ShowModifiers:
			builder.Append(GetModifier(property))

		if IncludeHTMLMarkup:
			builder.Append('')

		if UseFullyQualifiedMemberNames:
			builder.Append(property.FullyQualifiedName)
		else:
			builder.Append(property.Name)

		if IncludeHTMLMarkup:
			builder.Append('')

		if property.Parameters.Count > 0:
			builder.Append('(')
			if IncludeHTMLMarkup:
				builder.Append('
')

			for i in range(property.Parameters.Count):
				if IncludeHTMLMarkup:
					builder.Append('   ')

				builder.Append(Convert(property.Parameters[i]))
				if i + 1 < property.Parameters.Count:
					builder.Append(', ')

				if IncludeHTMLMarkup:
					builder.Append('
')

			builder.Append(')')

		if property.ReturnType != null and ShowReturnType:
			builder.Append(' as ')
			builder.Append(Convert(property.ReturnType))

		if IncludeBodies:
			builder.Append(': ')
			if property.CanGet:
				builder.Append('get ')

			if property.CanSet:
				builder.Append('set ')

		return builder.ToString()

	override def Convert(e as IEvent) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(e.Modifiers))
		if ShowModifiers:
			builder.Append(GetModifier(e))

		if IncludeHTMLMarkup:
			builder.Append('')

		if UseFullyQualifiedMemberNames:
			builder.Append(e.FullyQualifiedName)
		else:
			builder.Append(e.Name)

		if IncludeHTMLMarkup:
			builder.Append('')

		if e.ReturnType != null and ShowReturnType:
			builder.Append(' as ')
			builder.Append(Convert(e.ReturnType))

		return builder.ToString()

	override def Convert(m as IIndexer) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(m.Modifiers))
		if IncludeHTMLMarkup:
			builder.Append('')

		if ShowModifiers and m.IsStatic:
			builder.Append('static ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if m.ReturnType != null and ShowReturnType:
			builder.Append(Convert(m.ReturnType))
			builder.Append(' ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if UseFullyQualifiedMemberNames:
			builder.Append(m.FullyQualifiedName)
		else:
			builder.Append(m.Name)

		if IncludeHTMLMarkup:
			builder.Append('')

		builder.Append('Indexer(')
		if IncludeHTMLMarkup:
			builder.Append('
')

		for i in range(m.Parameters.Count):
			if IncludeHTMLMarkup:
				builder.Append('   ')

			builder.Append(Convert(m.Parameters[i]))
			if i + 1 < m.Parameters.Count:
				builder.Append(', ')

			if IncludeHTMLMarkup:
				builder.Append('
')

		builder.Append(')')

		return builder.ToString()

	override def Convert(m as IMethod) as string:
		builder as StringBuilder = StringBuilder()
		builder.Append(Convert(m.Modifiers))
		if ShowModifiers:
			builder.Append(GetModifier(m))

		builder.Append('def ') if ShowReturnType

		if IncludeHTMLMarkup:
			builder.Append('')

		if m.IsConstructor:
			builder.Append('constructor')
		else:
			if UseFullyQualifiedMemberNames:
				builder.Append(m.FullyQualifiedName)
			else:
				builder.Append(m.Name)

		if IncludeHTMLMarkup:
			builder.Append('')

		builder.Append('(')
		if IncludeHTMLMarkup:
			builder.Append('
')

		for i in range(m.Parameters.Count):
			if IncludeHTMLMarkup:
				builder.Append('   ')

			builder.Append(Convert(m.Parameters[i]))
			if i + 1 < m.Parameters.Count:
				builder.Append(', ')

			if IncludeHTMLMarkup:
				builder.Append('
')

		builder.Append(')')

		if m.ReturnType != null and ShowReturnType:
			builder.Append(' as ')
			builder.Append(Convert(m.ReturnType))

		if IncludeBodies:
			if m.DeclaringType != null:
				if m.DeclaringType.ClassType != ClassType.Interface:
					builder.Append(': ')
			else:
				builder.Append(': ')

		return builder.ToString()

	override def ConvertEnd(m as IMethod) as string:
		return ''

	override def Convert(returnType as IReturnType) as string:
		if returnType == null:
			return ''

		builder as StringBuilder = StringBuilder()
		/*
		linkSet as bool = false
		if UseLinkArrayList:
			ret as SharpAssemblyReturnType = returnType as SharpAssemblyReturnType
			if ret != null:
				if ret.UnderlyingClass != null:
					builder.Append('')
					linkSet = true
		*/

		for i in range(returnType.ArrayCount):
			builder.Append('(')

		if returnType.FullyQualifiedName != null and _typeConversionTable[returnType.FullyQualifiedName] != null:
			builder.Append(_typeConversionTable[returnType.FullyQualifiedName])
		else:
			if UseFullyQualifiedNames:
				builder.Append(returnType.FullyQualifiedName)
			else:
				builder.Append(returnType.Name)

		//if linkSet:
		//	builder.Append('')

		for i in range(returnType.PointerNestingLevel):
			builder.Append('*')

		for i in range(returnType.ArrayCount):
			builder.Append(')')
			/*
			builder.Append(Char.Parse('['))
			j as int = 1
			while j < returnType.ArrayDimensions[i]:
				builder.Append(Char.Parse(','))
				++j

			builder.Append(Char.Parse(']'))
			*/

		return builder.ToString()

	override def Convert(param as IParameter) as string:
		builder as StringBuilder = StringBuilder()
		if IncludeHTMLMarkup:
			builder.Append('')

		if param.IsRef:
			builder.Append('ref ')
		elif param.IsOut:
			builder.Append('out ')
		elif param.IsParams:
			builder.Append('params ')

		if IncludeHTMLMarkup:
			builder.Append('')

		if ShowParameterNames:
			builder.Append(param.Name)
			builder.Append(' as ')
		builder.Append(Convert(param.ReturnType))

		return builder.ToString()

	override def WrapAttribute(attribute as string) as string:
		return '[' + attribute + ']'

	override def WrapComment(comment as string) as string:
		return '// ' + comment

	override def GetIntrinsicTypeName(dotNetTypeName as string) as string:
		if _typeConversionTable[dotNetTypeName] != null:
			return _typeConversionTable[dotNetTypeName]
		return dotNetTypeName


WarningRegularExpression wasn't picking up warnings without lexical information (which is valid apparently)

git-svn-id: fcce7d6ce0ac15bf24f68871b5145d46fc068279@2392 2c1201b4-01cd-e047-a400-b836ae1fbc61

#region license
// Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//     * Neither the name of Rodrigo B. de Oliveira nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

namespace Boo.Microsoft.Build.Tasks

import Microsoft.Build.Framework
import Microsoft.Build.Tasks
import Microsoft.Build.Utilities
import System
import System.Diagnostics
import System.IO
import System.Globalization
import System.Text.RegularExpressions
import System.Threading

class Booc(ManagedCompiler):
"""
Represents the Boo compiler MSBuild task.

Authors:
	Sorin Ionescu (sorin.ionescu@gmail.com)
"""
	def constructor():
		NoLogo = true

	Pipeline:
	"""
	Gets/sets a specific pipeline to add to the compiler process.
	"""
		get:
			return Bag['Pipelines'] as string
		set:
			Bag['Pipelines'] = value
	NoStandardLib:
	"""
	Gets/sets if we want to link to the standard libraries or not.
	"""
		get:
			return GetBoolParameterWithDefault("NoStandardLib", false)
		set:
			Bag['NoStandardLib'] = value
	WhiteSpaceAgnostic:
	"""
	Gets/sets if we want to use whitespace agnostic mode.
	"""
		get:
			return GetBoolParameterWithDefault("WhiteSpaceAgnostic", false)
		set:
			Bag['WhiteSpaceAgnostic'] = value
	Ducky:
	"""
	Gets/sets if we want to use ducky mode.
	"""
		get:
			return GetBoolParameterWithDefault("Ducky", false)
		set:
			Bag['Ducky'] = value
	Verbosity:
	"""
	Gets/sets the verbosity level.
	"""
		get:
			return Bag['Verbosity'] as string
		set:
			Bag['Verbosity'] = value

	Culture:
	"""
	Gets/sets the culture.
	"""
		get:
			return Bag['Culture'] as string
		set:
			Bag['Culture'] = value

	SourceDirectory:
	"""
	Gets/sets the source directory.
	"""
		get:
			return Bag['Source Directory'] as string
		set:
			Bag['Source Directory'] = value

	ToolName:
	"""
	Gets the tool name.
	"""
		get:
			return "booc.exe"

	override def Execute():
	"""
	Executes the task.

	Returns:
		true if the task completed successfully; otherwise, false.
	"""
		boocCommandLine = CommandLineBuilderExtension()
		AddResponseFileCommands(boocCommandLine)

		warningPattern = regex(
			'^(?<file>.*?)(\\((?<line>\\d+),(?<column>\\d+)\\):)?' +
				'(\\s?)(?BCW\\d{4}):(\\s)WARNING:(\\s)(?<message>.*)$',
			RegexOptions.Compiled)
		# Captures the file, line, column, code, and message from a BOO warning
		# in the form of: Program.boo(1,1): BCW0000: WARNING: This is a warning.

		errorPattern = regex(
			'^(((?<file>.*?)\\((?<line>\\d+),(?<column>\\d+)\\): )?' +
				'(?BCE\\d{4})|(?<errorType>Fatal) error):' +
				'( Boo.Lang.Compiler.CompilerError:)?' +
				' (?<message>.*?)($| --->)',
			RegexOptions.Compiled |
				RegexOptions.ExplicitCapture |
				RegexOptions.Multiline)
		/*
		 * Captures the file, line, column, code, error type, and message from a
		 * BOO error of the form of:
		 * 1. Program.boo(1,1): BCE0000: This is an error.
		 * 2. Program.boo(1,1): BCE0000: Boo.Lang.Compiler.CompilerError:
		 *    	This is an error. ---> Program.boo:4:19: This is an error
		 * 3. BCE0000: This is an error.
		 * 4. Fatal error: This is an error.
		 *
		 * The second line of the following error format is not cought because
		 * .NET does not support if|then|else in regular expressions,
		 * and the regex will be horrible complicated.
		 * The second line is as worthless as the first line.
		 * Therefore, it is not worth implementing it.
		 *
		 * 	Fatal error: This is an error.
		 * 	Parameter name: format.
		 */

		buildSuccess = true
		outputLine = String.Empty
		errorLine = String.Empty
		readingDoneEvents = (ManualResetEvent(false), ManualResetEvent(false))

		boocProcessStartInfo = ProcessStartInfo(
			FileName: GenerateFullPathToTool(),
			Arguments: boocCommandLine.ToString(),
			ErrorDialog: false,
			CreateNoWindow: true,
			RedirectStandardError: true,
			RedirectStandardInput: false,
			RedirectStandardOutput: true,
			UseShellExecute: false)

		boocProcess = Process(StartInfo: boocProcessStartInfo)

		parseOutput = def(line as string):
			warningPatternMatch = warningPattern.Match(line)
			errorPatternMatch = errorPattern.Match(line)

			if warningPatternMatch.Success:
				lineOut = 0
				columnOut = 0
				int.TryParse(warningPatternMatch.Groups['line'].Value, lineOut)
				int.TryParse(warningPatternMatch.Groups['column'].Value, columnOut)
				Log.LogWarning(
					null,
					warningPatternMatch.Groups['code'].Value,
					null,
					warningPatternMatch.Groups['file'].Value,
					lineOut,
					columnOut,
					0,
					0,
					warningPatternMatch.Groups['message'].Value)

			elif errorPatternMatch.Success:
				code = errorPatternMatch.Groups['code'].Value
				code = 'BCE0000' if string.IsNullOrEmpty(code)
				file = errorPatternMatch.Groups['file'].Value
				file = 'BOOC' if string.IsNullOrEmpty(file)

				try:
					lineNumber = int.Parse(
						errorPatternMatch.Groups['line'].Value,
						NumberStyles.Integer)

				except FormatException:
					lineNumber = 0

				try:
					columnNumber = int.Parse(
						errorPatternMatch.Groups['column'].Value,
						NumberStyles.Integer)

				except FormatException:
					columnNumber = 0

				Log.LogError(
					errorPatternMatch.Groups['errorType'].Value.ToLower(),
					code,
					null,
					file,
					lineNumber,
					columnNumber,
					0,
					0,
					errorPatternMatch.Groups['message'].Value)

				buildSuccess = false

			else:
				Log.LogMessage(MessageImportance.Normal, line)

		readStandardOutput = def():
			while true:
				outputLine = boocProcess.StandardOutput.ReadLine()

				if outputLine:
					parseOutput(outputLine)

				else:
					readingDoneEvents[0].Set()
					break

		readStandardError = def():
			while true:
				errorLine = boocProcess.StandardError.ReadLine()

				if errorLine:
					parseOutput(errorLine)

				else:
					readingDoneEvents[1].Set()
					break

		standardOutputReadingThread = Thread(readStandardOutput as ThreadStart)
		standardErrorReadingThread = Thread(readStandardError as ThreadStart)
		# Two threads are required (MSDN); otherwise, a deadlock WILL occur.

		try:
			boocProcess.Start()

			Log.LogMessage(
				MessageImportance.High,
				"${ToolName} ${boocProcess.StartInfo.Arguments}",
				null)

			standardOutputReadingThread.Start()
			standardErrorReadingThread.Start()

			WaitHandle.WaitAny((readingDoneEvents[0],))
			WaitHandle.WaitAny((readingDoneEvents[1],))
			# MSBuild runs on an STA thread, and WaitHandle.WaitAll()
			# is not supported.

		except e as Exception:
			Log.LogErrorFromException(e)
			buildSuccess = false

		ensure:
			boocProcess.Close()

		return buildSuccess

	protected override def AddCommandLineCommands(
		commandLine as CommandLineBuilderExtension):
	"""
	Adds command line commands.

	Remarks:
		It prevents <ManagedCompiler> from adding the standard commands.
	"""
			pass

	protected override def AddResponseFileCommands(
		commandLine as CommandLineBuilderExtension):
	"""
	Generates the Boo compiler command line.

	Returns:
		The Boo compiler command line.
	"""
		commandLine.AppendSwitchIfNotNull('-t:', TargetType)
		commandLine.AppendSwitchIfNotNull('-o:', OutputAssembly)
		commandLine.AppendSwitchIfNotNull('-c:', Culture)
		commandLine.AppendSwitchIfNotNull('-srcdir:', SourceDirectory)
		commandLine.AppendSwitchIfNotNull('-keyfile:', KeyFile)
		commandLine.AppendSwitchIfNotNull('-keycontainer:', KeyContainer)
		commandLine.AppendSwitchIfNotNull('-p:', Pipeline)
		commandLine.AppendSwitchIfNotNull("-lib:", AdditionalLibPaths, ",")

		if NoLogo:
			commandLine.AppendSwitch('-nologo')
		if NoConfig:
			commandLine.AppendSwitch('-noconfig')
		if NoStandardLib:
			commandLine.AppendSwitch('-nostdlib')
		if DelaySign:
			commandLine.AppendSwitch('-delaysign')
		if WhiteSpaceAgnostic:
			commandLine.AppendSwitch('-wsa')
		if Ducky:
			commandLine.AppendSwitch('-ducky')

		if EmitDebugInformation:
			commandLine.AppendSwitch('-debug')
		else:
			commandLine.AppendSwitch('-debug-')

		if ResponseFiles:
			for rsp in ResponseFiles:
				commandLine.AppendSwitchIfNotNull("@", rsp.ItemSpec)

		if References:
			for reference in References:
				commandLine.AppendSwitchIfNotNull('-r:', reference.ItemSpec)

		if Resources:
			for resource in Resources:
				commandLine.AppendSwitchIfNotNull('-resource:', resource.ItemSpec)

		if Verbosity:
			if string.Compare(
					Verbosity,
					'Normal',
					StringComparison.InvariantCultureIgnoreCase) == 0:
				pass

			elif string.Compare(
					Verbosity,
					'Warning',
					StringComparison.InvariantCultureIgnoreCase) == 0:

				commandLine.AppendSwitch('-v')

			elif string.Compare(
					Verbosity,
					'Info',
					StringComparison.InvariantCultureIgnoreCase) == 0:

				commandLine.AppendSwitch('-vv')

			elif string.Compare(
					Verbosity,
					'Verbose',
					StringComparison.InvariantCultureIgnoreCase) == 0:

				commandLine.AppendSwitch('-vvv')

			else:
				Log.LogErrorWithCodeFromResources(
					'Vbc.EnumParameterHasInvalidValue',
					'Verbosity',
					Verbosity,
					'Normal, Warning, Info, Verbose')

		commandLine.AppendFileNamesIfNotNull(Sources, ' ')

	protected override def GenerateFullPathToTool():
	"""
	Generats the full path to booc.exe.
	"""
		path = ""

		if ToolPath:
			path = Path.Combine(ToolPath, ToolName)

		return path if File.Exists(path)

		path = Path.Combine(
			Path.GetDirectoryName(typeof(Booc).Assembly.Location),
			ToolName)

		return path if File.Exists(path)

		path = ToolLocationHelper.GetPathToDotNetFrameworkFile(
			ToolName,
			TargetDotNetFrameworkVersion.VersionLatest)

		return path if File.Exists(path)

		/* //removed this error message for mono compatibility
		Log.LogErrorWithCodeFromResources(
			"General.FrameworksFileNotFound",
			ToolName,
			ToolLocationHelper.GetDotNetFrameworkVersionFolderPrefix(
				TargetDotNetFrameworkVersion.Version20))
		*/
		path = "booc"

		return path

#region license
// Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//     * Neither the name of Rodrigo B. de Oliveira nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

namespace Boo.Microsoft.Build.Tasks

import Microsoft.Build.Framework
import Microsoft.Build.Tasks
import Microsoft.Build.Utilities
import System
import System.Diagnostics
import System.IO
import System.Globalization
import System.Text.RegularExpressions
import System.Threading

class Booc(ManagedCompiler):
"""
Represents the Boo compiler MSBuild task.

Authors:
	Sorin Ionescu (sorin.ionescu@gmail.com)
"""
	def constructor():
		NoLogo = true

	Pipeline:
	"""
	Gets/sets a specific pipeline to add to the compiler process.
	"""
		get:
			return Bag['Pipelines'] as string
		set:
			Bag['Pipelines'] = value
	NoStandardLib:
	"""
	Gets/sets if we want to link to the standard libraries or not.
	"""
		get:
			return GetBoolParameterWithDefault("NoStandardLib", false)
		set:
			Bag['NoStandardLib'] = value
	WhiteSpaceAgnostic:
	"""
	Gets/sets if we want to use whitespace agnostic mode.
	"""
		get:
			return GetBoolParameterWithDefault("WhiteSpaceAgnostic", false)
		set:
			Bag['WhiteSpaceAgnostic'] = value
	Ducky:
	"""
	Gets/sets if we want to use ducky mode.
	"""
		get:
			return GetBoolParameterWithDefault("Ducky", false)
		set:
			Bag['Ducky'] = value
	Verbosity:
	"""
	Gets/sets the verbosity level.
	"""
		get:
			return Bag['Verbosity'] as string
		set:
			Bag['Verbosity'] = value

	Culture:
	"""
	Gets/sets the culture.
	"""
		get:
			return Bag['Culture'] as string
		set:
			Bag['Culture'] = value

	SourceDirectory:
	"""
	Gets/sets the source directory.
	"""
		get:
			return Bag['Source Directory'] as string
		set:
			Bag['Source Directory'] = value

	ToolName:
	"""
	Gets the tool name.
	"""
		get:
			return "booc.exe"

	override def Execute():
	"""
	Executes the task.

	Returns:
		true if the task completed successfully; otherwise, false.
	"""
		boocCommandLine = CommandLineBuilderExtension()
		AddResponseFileCommands(boocCommandLine)

		warningPattern = regex(
			'^(?<file>.*?)\\((?<line>\\d+),(?<column>\\d+)\\):' +
				' (?BCW\\d{4}): WARNING: (?<message>.*)$',
			RegexOptions.Compiled)
		# Captures the file, line, column, code, and message from a BOO warning
		# in the form of: Program.boo(1,1): BCW0000: WARNING: This is a warning.

		errorPattern = regex(
			'^(((?<file>.*?)\\((?<line>\\d+),(?<column>\\d+)\\): )?' +
				'(?BCE\\d{4})|(?<errorType>Fatal) error):' +
				'( Boo.Lang.Compiler.CompilerError:)?' +
				' (?<message>.*?)($| --->)',
			RegexOptions.Compiled |
				RegexOptions.ExplicitCapture |
				RegexOptions.Multiline)
		/*
		 * Captures the file, line, column, code, error type, and message from a
		 * BOO error of the form of:
		 * 1. Program.boo(1,1): BCE0000: This is an error.
		 * 2. Program.boo(1,1): BCE0000: Boo.Lang.Compiler.CompilerError:
		 *    	This is an error. ---> Program.boo:4:19: This is an error
		 * 3. BCE0000: This is an error.
		 * 4. Fatal error: This is an error.
		 *
		 * The second line of the following error format is not cought because
		 * .NET does not support if|then|else in regular expressions,
		 * and the regex will be horrible complicated.
		 * The second line is as worthless as the first line.
		 * Therefore, it is not worth implementing it.
		 *
		 * 	Fatal error: This is an error.
		 * 	Parameter name: format.
		 */

		buildSuccess = true
		outputLine = String.Empty
		errorLine = String.Empty
		readingDoneEvents = (ManualResetEvent(false), ManualResetEvent(false))

		boocProcessStartInfo = ProcessStartInfo(
			FileName: GenerateFullPathToTool(),
			Arguments: boocCommandLine.ToString(),
			ErrorDialog: false,
			CreateNoWindow: true,
			RedirectStandardError: true,
			RedirectStandardInput: false,
			RedirectStandardOutput: true,
			UseShellExecute: false)

		boocProcess = Process(StartInfo: boocProcessStartInfo)

		parseOutput = def(line as string):
			warningPatternMatch = warningPattern.Match(line)
			errorPatternMatch = errorPattern.Match(line)

			if warningPatternMatch.Success:
				Log.LogWarning(
					null,
					warningPatternMatch.Groups['code'].Value,
					null,
					warningPatternMatch.Groups['file'].Value,
					int.Parse(warningPatternMatch.Groups['line'].Value),
					int.Parse(warningPatternMatch.Groups['column'].Value),
					0,
					0,
					warningPatternMatch.Groups['message'].Value)

			elif errorPatternMatch.Success:
				code = errorPatternMatch.Groups['code'].Value
				code = 'BCE0000' if string.IsNullOrEmpty(code)
				file = errorPatternMatch.Groups['file'].Value
				file = 'BOOC' if string.IsNullOrEmpty(file)

				try:
					lineNumber = int.Parse(
						errorPatternMatch.Groups['line'].Value,
						NumberStyles.Integer)

				except FormatException:
					lineNumber = 0

				try:
					columnNumber = int.Parse(
						errorPatternMatch.Groups['column'].Value,
						NumberStyles.Integer)

				except FormatException:
					columnNumber = 0

				Log.LogError(
					errorPatternMatch.Groups['errorType'].Value.ToLower(),
					code,
					null,
					file,
					lineNumber,
					columnNumber,
					0,
					0,
					errorPatternMatch.Groups['message'].Value)

				buildSuccess = false

			else:
				Log.LogMessage(MessageImportance.Normal, line)

		readStandardOutput = def():
			while true:
				outputLine = boocProcess.StandardOutput.ReadLine()

				if outputLine:
					parseOutput(outputLine)

				else:
					readingDoneEvents[0].Set()
					break

		readStandardError = def():
			while true:
				errorLine = boocProcess.StandardError.ReadLine()

				if errorLine:
					parseOutput(errorLine)

				else:
					readingDoneEvents[1].Set()
					break

		standardOutputReadingThread = Thread(readStandardOutput as ThreadStart)
		standardErrorReadingThread = Thread(readStandardError as ThreadStart)
		# Two threads are required (MSDN); otherwise, a deadlock WILL occur.

		try:
			boocProcess.Start()

			Log.LogMessage(
				MessageImportance.High,
				"${ToolName} ${boocProcess.StartInfo.Arguments}",
				null)

			standardOutputReadingThread.Start()
			standardErrorReadingThread.Start()

			WaitHandle.WaitAny((readingDoneEvents[0],))
			WaitHandle.WaitAny((readingDoneEvents[1],))
			# MSBuild runs on an STA thread, and WaitHandle.WaitAll()
			# is not supported.

		except e as Exception:
			Log.LogErrorFromException(e)
			buildSuccess = false

		ensure:
			boocProcess.Close()

		return buildSuccess

	protected override def AddCommandLineCommands(
		commandLine as CommandLineBuilderExtension):
	"""
	Adds command line commands.

	Remarks:
		It prevents <ManagedCompiler> from adding the standard commands.
	"""
			pass

	protected override def AddResponseFileCommands(
		commandLine as CommandLineBuilderExtension):
	"""
	Generates the Boo compiler command line.

	Returns:
		The Boo compiler command line.
	"""
		commandLine.AppendSwitchIfNotNull('-t:', TargetType)
		commandLine.AppendSwitchIfNotNull('-o:', OutputAssembly)
		commandLine.AppendSwitchIfNotNull('-c:', Culture)
		commandLine.AppendSwitchIfNotNull('-srcdir:', SourceDirectory)
		commandLine.AppendSwitchIfNotNull('-keyfile:', KeyFile)
		commandLine.AppendSwitchIfNotNull('-keycontainer:', KeyContainer)
		commandLine.AppendSwitchIfNotNull('-p:', Pipeline)
		commandLine.AppendSwitchIfNotNull("-lib:", AdditionalLibPaths, ",")

		if NoLogo:
			commandLine.AppendSwitch('-nologo')
		if NoConfig:
			commandLine.AppendSwitch('-noconfig')
		if NoStandardLib:
			commandLine.AppendSwitch('-nostdlib')
		if DelaySign:
			commandLine.AppendSwitch('-delaysign')
		if WhiteSpaceAgnostic:
			commandLine.AppendSwitch('-wsa')
		if Ducky:
			commandLine.AppendSwitch('-ducky')

		if EmitDebugInformation:
			commandLine.AppendSwitch('-debug')
		else:
			commandLine.AppendSwitch('-debug-')

		if ResponseFiles:
			for rsp in ResponseFiles:
				commandLine.AppendSwitchIfNotNull("@", rsp.ItemSpec)

		if References:
			for reference in References:
				commandLine.AppendSwitchIfNotNull('-r:', reference.ItemSpec)

		if Resources:
			for resource in Resources:
				commandLine.AppendSwitchIfNotNull('-resource:', resource.ItemSpec)

		if Verbosity:
			if string.Compare(
					Verbosity,
					'Normal',
					StringComparison.InvariantCultureIgnoreCase) == 0:
				pass

			elif string.Compare(
					Verbosity,
					'Warning',
					StringComparison.InvariantCultureIgnoreCase) == 0:

				commandLine.AppendSwitch('-v')

			elif string.Compare(
					Verbosity,
					'Info',
					StringComparison.InvariantCultureIgnoreCase) == 0:

				commandLine.AppendSwitch('-vv')

			elif string.Compare(
					Verbosity,
					'Verbose',
					StringComparison.InvariantCultureIgnoreCase) == 0:

				commandLine.AppendSwitch('-vvv')

			else:
				Log.LogErrorWithCodeFromResources(
					'Vbc.EnumParameterHasInvalidValue',
					'Verbosity',
					Verbosity,
					'Normal, Warning, Info, Verbose')

		commandLine.AppendFileNamesIfNotNull(Sources, ' ')

	protected override def GenerateFullPathToTool():
	"""
	Generats the full path to booc.exe.
	"""
		path = ""

		if ToolPath:
			path = Path.Combine(ToolPath, ToolName)

		return path if File.Exists(path)

		path = Path.Combine(
			Path.GetDirectoryName(typeof(Booc).Assembly.Location),
			ToolName)

		return path if File.Exists(path)

		path = ToolLocationHelper.GetPathToDotNetFrameworkFile(
			ToolName,
			TargetDotNetFrameworkVersion.VersionLatest)

		return path if File.Exists(path)

		/* //removed this error message for mono compatibility
		Log.LogErrorWithCodeFromResources(
			"General.FrameworksFileNotFound",
			ToolName,
			ToolLocationHelper.GetDotNetFrameworkVersionFolderPrefix(
				TargetDotNetFrameworkVersion.Version20))
		*/
		path = "booc"

		return path


unnecessary colon

unnecessary colon

git-svn-id: fcce7d6ce0ac15bf24f68871b5145d46fc068279@2955 2c1201b4-01cd-e047-a400-b836ae1fbc61

"""
caught!
should have passed here first!
should end up here!

"""
try:
	raise System.ApplicationException("caught!")
	print("should not get here!")
except x:
	print(x.Message)
ensure:
	print("should have passed here first!")
print("should end up here!");