fixed BOO-202

fixed BOO-202

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

#region license
// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de)
// All rights reserved.
//
// BooBinding is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Boo Explorer is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Foobar; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#endregion

namespace BooBinding

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

import ICSharpCode.Core.Services

import ICSharpCode.SharpDevelop.Internal.Project
import ICSharpCode.SharpDevelop.Gui
import ICSharpCode.SharpDevelop.Services

class BooBindingCompilerManager:
	static _normalError  = /(?<file>.*)\((?<line>\d+),(?<column>\d+)\):\s+(?<number>[\d\w]+):\s+(?<message>.*)/
	static _generalError = /(?<error>.+)\s+(?<number>[\d\w]+):\s+(?<message>.*)/

	def GetCompiledOutputName(fileName as string) as string:
		return Path.ChangeExtension(fileName, ".exe")

	def GetCompiledOutputName(project as IProject) as string:
		p as BooProject = project;
		compilerparameters as BooCompilerParameters = p.ActiveConfiguration

		fileUtilityService as FileUtilityService = ServiceManager.Services.GetService(typeof(FileUtilityService))
		exe = fileUtilityService.GetDirectoryNameWithSeparator(compilerparameters.OutputDirectory) + compilerparameters.OutputAssembly
		if (compilerparameters.CompileTarget == CompileTarget.Library):
			return exe + ".dll"
		else:
			return exe + ".exe"

	def CanCompile(fileName as string) as bool:
		return Path.GetExtension(fileName).ToLower() == ".boo";

	static _compilerNotFound = "Boo compiler not found.\nYou have to specify the path where booc.exe is in the project options!\n"

	private def MakeError(text as string):
		cr = CompilerResults(TempFileCollection())
		cr.Errors.Add(CompilerError(ErrorText: text))
		return DefaultCompilerResult(cr, text)

	private def Compile(compilerparameters as BooCompilerParameters, fileNames as (string), outputFile as string, p as IProject) as ICompilerResult:
		fileUtilityService as FileUtilityService = ServiceManager.Services.GetService(typeof(FileUtilityService))
		messageService as IMessageService = ServiceManager.Services.GetService(typeof(IMessageService))

		if compilerparameters.BooPath == "":
			messageService.ShowError(_compilerNotFound)
			return MakeError(_compilerNotFound)
		booDir = fileUtilityService.GetDirectoryNameWithSeparator(compilerparameters.BooPath)
		compilerName = booDir + "booc.exe"

		if not File.Exists(compilerName):
			messageService.ShowError(_compilerNotFound)
			return MakeError(_compilerNotFound)

		cmd = StringBuilder()
		cmd.Append("\"${compilerName}\"")

		cmd.Append(" -o:\"${outputFile}\"")

		cmd.Append(" -vv") if compilerparameters.Verbose

		cmd.Append(" -t:")
		if (compilerparameters.CompileTarget == CompileTarget.WinExe):
			cmd.Append("winexe")
		else:
			if (compilerparameters.CompileTarget == CompileTarget.Library):
				cmd.Append("library");
			else:
				cmd.Append("exe");

		// Default references are already added by booc.rsp

		if p != null:
			// write references
			for lib as ProjectReference in p.ProjectReferences:
				cmd.Append(" \"-r:${lib.GetReferencedFileName(p)}\"");
			// write embedded resources
			for finfo as ProjectFile in p.ProjectFiles:
				if finfo.Subtype != Subtype.Directory and finfo.BuildAction == BuildAction.EmbedAsResource:
					cmd.Append(" \"-resource:${finfo.Name}\"")

		for fileName as string in fileNames:
			cmd.Append(" \"${Path.GetFullPath(fileName)}\"")

		outstr = cmd.ToString()
		tf = TempFileCollection()
		output = ""
		error = ""
		Executor.ExecWaitWithCapture(outstr, Path.GetFullPath(compilerparameters.OutputDirectory), tf, output, error)

		result = ParseOutput(tf, output)

		outputDirectory = Path.GetDirectoryName(outputFile)

		CopyToDirIgnoringErrors(Path.Combine(booDir, "Boo.dll"), outputDirectory)
		for lib as ProjectReference in p.ProjectReferences:
			if lib.LocalCopy:
				CopyToDirIgnoringErrors(
					lib.GetReferencedFileName(p),
					outputDirectory)

		File.Delete(output)
		File.Delete(error)
		return result

	def CopyToDirIgnoringErrors(fname as string, outputDirectory as string):
		try:
			File.Copy(fname, Path.Combine(outputDirectory, Path.GetFileName(fname)))
		except:
			pass

	def CompileFile(fileName as string, compilerparameters as BooCompilerParameters) as ICompilerResult:
		compilerparameters.OutputDirectory = Path.GetDirectoryName(fileName)
		compilerparameters.OutputAssembly  = Path.GetFileNameWithoutExtension(fileName)

		return Compile(compilerparameters, (fileName,), GetCompiledOutputName(fileName), null)

	def CompileProject(project as BooProject) as ICompilerResult:
		compilerparameters as BooCompilerParameters = project.ActiveConfiguration

		fileNames = ArrayList()

		for	finfo as ProjectFile in project.ProjectFiles:
			if finfo.Subtype != Subtype.Directory:
				if finfo.BuildAction == BuildAction.Compile:
						fileNames.Add(finfo.Name)

		exe = GetCompiledOutputName(project)
		if compilerparameters.CompileTarget == CompileTarget.WinExe:
			WriteManifestFile(exe)

		return Compile(compilerparameters, fileNames.ToArray(typeof(string)), exe, project)

	def WriteManifestFile(fileName as string):
		manifestFile = fileName + ".manifest"
		return if File.Exists(manifestFile)
		using sw = StreamWriter(manifestFile):
			sw.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
			sw.WriteLine("")
			sw.WriteLine("<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">")
			sw.WriteLine("	<dependency>")
			sw.WriteLine("		<dependentAssembly>")
			sw.WriteLine("			<assemblyIdentity")
			sw.WriteLine("				type=\"win32\"")
			sw.WriteLine("				name=\"Microsoft.Windows.Common-Controls\"")
			sw.WriteLine("				version=\"6.0.0.0\"")
			sw.WriteLine("				processorArchitecture=\"X86\"")
			sw.WriteLine("				publicKeyToken=\"6595b64144ccf1df\"")
			sw.WriteLine("				language=\"*\"")
			sw.WriteLine("			/>")
			sw.WriteLine("		</dependentAssembly>")
			sw.WriteLine("	</dependency>")
			sw.WriteLine("</assembly>")

	def ParseOutput(tf as TempFileCollection, file as string) as ICompilerResult:
		compilerOutput = StringBuilder();

		using sr = File.OpenText(file):
			cr = CompilerResults(tf)

			curLine = sr.ReadLine()
			while curLine != null:
				compilerOutput.Append(curLine)
				compilerOutput.Append("\n")
				curLine = curLine.Trim();
				if curLine.Length == 0:
					curLine = sr.ReadLine()
					continue

				error = CompilerError()

				// try to match standard errors
				match = _normalError.Match(curLine)
				if match.Success:
					error.Column      = Int32.Parse(match.Result('${column}'));
					error.Line        = Int32.Parse(match.Result('${line}'));
					error.FileName    = Path.GetFullPath(match.Result('${file}'));
					error.ErrorNumber = match.Result('${number}');
					error.IsWarning   = error.ErrorNumber.StartsWith("BCW")
					error.ErrorText   = match.Result('${message}');
				else:
					match = _generalError.Match(curLine); // try to match general csc errors
					if match.Success:
						error.IsWarning   = match.Result('${error}') == "warning";
						error.ErrorNumber = match.Result('${number}');
						error.ErrorText   = match.Result('${message}');
					else:
						// give up and skip the line
						curLine = sr.ReadLine()
						continue

				cr.Errors.Add(error);

				curLine = sr.ReadLine()
		return DefaultCompilerResult(cr, compilerOutput.ToString())

#region license
// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de)
// All rights reserved.
//
// BooBinding is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Boo Explorer is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Foobar; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#endregion

namespace BooBinding

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

import ICSharpCode.Core.Services

import ICSharpCode.SharpDevelop.Internal.Project
import ICSharpCode.SharpDevelop.Gui
import ICSharpCode.SharpDevelop.Services

class BooBindingCompilerManager:
	static _normalError  = /(?<file>.*)\((?<line>\d+),(?<column>\d+)\):\s+(?<number>[\d\w]+):\s+(?<message>.*)/
	static _generalError = /(?<error>.+)\s+(?<number>[\d\w]+):\s+(?<message>.*)/

	def GetCompiledOutputName(fileName as string) as string:
		return Path.ChangeExtension(fileName, ".exe")

	def GetCompiledOutputName(project as IProject) as string:
		p as BooProject = project;
		compilerparameters as BooCompilerParameters = p.ActiveConfiguration

		fileUtilityService as FileUtilityService = ServiceManager.Services.GetService(typeof(FileUtilityService))
		exe = fileUtilityService.GetDirectoryNameWithSeparator(compilerparameters.OutputDirectory) + compilerparameters.OutputAssembly
		if (compilerparameters.CompileTarget == CompileTarget.Library):
			return exe + ".dll"
		else:
			return exe + ".exe"

	def CanCompile(fileName as string) as bool:
		return Path.GetExtension(fileName).ToLower() == ".boo";

	static _compilerNotFound = "Boo compiler not found.\nYou have to specify the path where booc.exe is in the project options!\n"

	private def MakeError(text as string):
		cr = CompilerResults(TempFileCollection())
		cr.Errors.Add(CompilerError(ErrorText: text))
		return DefaultCompilerResult(cr, text)

	private def Compile(compilerparameters as BooCompilerParameters, fileNames as (string), outputFile as string, p as IProject) as ICompilerResult:
		fileUtilityService as FileUtilityService = ServiceManager.Services.GetService(typeof(FileUtilityService))
		messageService as IMessageService = ServiceManager.Services.GetService(typeof(IMessageService))

		if compilerparameters.BooPath == "":
			messageService.ShowError(_compilerNotFound)
			return MakeError(_compilerNotFound)
		booDir = fileUtilityService.GetDirectoryNameWithSeparator(compilerparameters.BooPath)
		compilerName = booDir + "booc.exe"

		if not File.Exists(compilerName):
			messageService.ShowError(_compilerNotFound)
			return MakeError(_compilerNotFound)

		cmd = StringBuilder()
		cmd.Append("\"${compilerName}\"")

		cmd.Append(" -o:\"${outputFile}\"")

		cmd.Append(" -vv") if compilerparameters.Verbose

		cmd.Append(" -t:")
		if (compilerparameters.CompileTarget == CompileTarget.WinExe):
			cmd.Append("winexe")
		else:
			if (compilerparameters.CompileTarget == CompileTarget.Library):
				cmd.Append("library");
			else:
				cmd.Append("exe");

		// Default references are already added by booc.rsp

		if p != null:
			// write references
			for lib as ProjectReference in p.ProjectReferences:
				cmd.Append(" \"-r:${lib.GetReferencedFileName(p)}\"");
			// write embedded resources
			for finfo as ProjectFile in p.ProjectFiles:
				if finfo.Subtype != Subtype.Directory and finfo.BuildAction == BuildAction.EmbedAsResource:
					cmd.Append(" \"-resource:${finfo.Name}\"")

		for fileName as string in fileNames:
			cmd.Append(" \"${Path.GetFullPath(fileName)}\"")

		outstr = cmd.ToString()
		tf = TempFileCollection()
		output = ""
		error = ""
		Executor.ExecWaitWithCapture(outstr, Path.GetFullPath(compilerparameters.OutputDirectory), tf, output, error)

		result = ParseOutput(tf, output)

		outputDirectory = Path.GetDirectoryName(outputFile)

		CopyToDirIgnoringErrors(Path.Combine(booDir, "Boo.dll"), outputDirectory)
		for lib as ProjectReference in p.ProjectReferences:
			if lib.LocalCopy:
				CopyToDirIgnoringErrors(
					lib.GetReferencedFileName(p),
					outputDirectory)

		File.Delete(output)
		File.Delete(error)
		return result

	def CopyToDirIgnoringErrors(fname as string, outputDirectory as string):
		try:
			File.Copy(fname, Path.Combine(outputDirectory, Path.GetFileName(fname)))
		except:
			pass

	def CompileFile(fileName as string, compilerparameters as BooCompilerParameters) as ICompilerResult:
		compilerparameters.OutputDirectory = Path.GetDirectoryName(fileName)
		compilerparameters.OutputAssembly  = Path.GetFileNameWithoutExtension(fileName)

		return Compile(compilerparameters, (fileName,), GetCompiledOutputName(fileName), null)

	def CompileProject(project as BooProject) as ICompilerResult:
		compilerparameters as BooCompilerParameters = project.ActiveConfiguration

		fileNames = ArrayList()

		for	finfo as ProjectFile in project.ProjectFiles:
			if finfo.Subtype != Subtype.Directory:
				if finfo.BuildAction == BuildAction.Compile:
						fileNames.Add(finfo.Name)

		exe = GetCompiledOutputName(project)
		if compilerparameters.CompileTarget == CompileTarget.WinExe:
			WriteManifestFile(exe)

		return Compile(compilerparameters, fileNames.ToArray(typeof(string)), exe, project)

	def WriteManifestFile(fileName as string):
		manifestFile = fileName + ".manifest"
		return if File.Exists(manifestFile)
		using sw = StreamWriter(manifestFile):
			sw.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
			sw.WriteLine("")
			sw.WriteLine("<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">")
			sw.WriteLine("	<dependency>")
			sw.WriteLine("		<dependentAssembly>")
			sw.WriteLine("			<assemblyIdentity")
			sw.WriteLine("				type=\"win32\"")
			sw.WriteLine("				name=\"Microsoft.Windows.Common-Controls\"")
			sw.WriteLine("				version=\"6.0.0.0\"")
			sw.WriteLine("				processorArchitecture=\"X86\"")
			sw.WriteLine("				publicKeyToken=\"6595b64144ccf1df\"")
			sw.WriteLine("				language=\"*\"")
			sw.WriteLine("			/>")
			sw.WriteLine("		</dependentAssembly>")
			sw.WriteLine("	</dependency>")
			sw.WriteLine("</assembly>")

	def ParseOutput(tf as TempFileCollection, file as string) as ICompilerResult:
		compilerOutput = StringBuilder();

		using sr = File.OpenText(file):
			cr = CompilerResults(tf)

			curLine = sr.ReadLine()
			while curLine != null:
				compilerOutput.Append(curLine)
				compilerOutput.Append("\n")
				curLine = curLine.Trim();
				if curLine.Length == 0:
					curLine = sr.ReadLine()
					continue

				error = CompilerError()

				// try to match standard errors
				match = _normalError.Match(curLine)
				if match.Success:
					error.Column      = Int32.Parse(match.Result('${column}'));
					error.Line        = Int32.Parse(match.Result('${line}'));
					error.FileName    = Path.GetFullPath(match.Result('${file}'));
					//error.IsWarning   = match.Result('${error}') == "warning";
					error.ErrorNumber = match.Result('${number}');
					error.ErrorText   = match.Result('${message}');
				else:
					match = _generalError.Match(curLine); // try to match general csc errors
					if match.Success:
						error.IsWarning   = match.Result('${error}') == "warning";
						error.ErrorNumber = match.Result('${number}');
						error.ErrorText   = match.Result('${message}');
					else:
						// give up and skip the line
						curLine = sr.ReadLine()
						continue

				cr.Errors.Add(error);

				curLine = sr.ReadLine()
		return DefaultCompilerResult(cr, compilerOutput.ToString())


updated to compile with the latest code

updated to compile with the latest code

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

#region license
// Copyright (c) 2003, 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

namespace StyleChecker

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps
import Boo.Lang.Compiler.Pipelines

class StyleCheckerStep(AbstractVisitorCompilerStep):

	override def Run():
		Visit(CompileUnit)

	override def LeaveClassDefinition(node as ClassDefinition):
		if not System.Char.IsUpper(node.Name[0]):
			AddError(node, "Class name '${node.Name}' does not start with uppercase letter!")

	override def LeaveField(node as Field):
		if not node.IsPublic:
			if not node.Name.StartsWith("_"):
				AddError(node, "Field name '${node.Name}' does not start with '_'!")

	override def LeaveParameterDeclaration(node as ParameterDeclaration):
		if not System.Char.IsLower(node.Name[0]):
			AddError(node, "Parameter name '${node.Name}' does not start with lowercase letter!")

	def AddError(node as Node, message as string):
		Errors.Add(CompilerError(node, message))

class StyleCheckerPipeline(CompileToFile):

	def constructor():
		self.Insert(1, StyleCheckerStep())

#region license
// Copyright (c) 2003, 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

namespace StyleChecker

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps
import Boo.Lang.Compiler.Pipelines

class StyleCheckerStep(AbstractVisitorCompilerStep):

	override def Run():
		Visit(CompileUnit)

	override def LeaveClassDefinition(node as ClassDefinition):
		if not System.Char.IsUpper(node.Name[0]):
			Error(node, "Class name '${node.Name}' does not start with uppercase letter!")

	override def LeaveField(node as Field):
		if not node.IsPublic:
			if not node.Name.StartsWith("_"):
				Error(node, "Field name '${node.Name}' does not start with '_'!")

	override def LeaveParameterDeclaration(node as ParameterDeclaration):
		if not System.Char.IsLower(node.Name[0]):
			Error(node, "Parameter name '${node.Name}' does not start with lowercase letter!")

	def Error(node as Node, message as string):
		Errors.Add(CompilerError(node, message))

class StyleCheckerPipeline(CompileToFile):

	def constructor():
		self.Insert(1, StyleCheckerStep())


removed warning

removed warning

namespace metaboo

import Boo.OMeta
import Boo.PatternMatching
import Boo.Lang.Compiler.Ast
import Boo.OMeta.Parser

def printTokens(text as string):
	printTokens BooParser(), text

def printTokens(grammar as OMetaGrammar, text as string):
	sep = "=" * 20
	print sep
	for token in scan(grammar, 'scanner', text):
		print token
	print sep

#print Tokenizer().indentation(" \n  foo")

printTokens """
class class0:

	class Bar:
		pass

	def foo():
		a = 3
		a = 4
"""

code = """
class Foo:
	def foo():
		a = 3
class Bar:
	class Baz:
		pass
	class Gazong:
		pass
"""
#printTokens code
#print BooParser().module(code)

code = """def foo():
	a = 3
	return bar(a)
"""
#printTokens code
match BooParser().method(code):
	case SuccessfulMatch(Input: OMetaInput(IsEmpty: true), Value: m=Method()):
		print m.ToCodeString()

code = """
class Foo:
def foo():
a = 3
return a
end
end
"""
#printTokens WSABooParser(), code
match WSABooParser().Apply('module', code):
	case SuccessfulMatch(Value: mod=Module()):
		print mod.ToCodeString()
	case FailedMatch(Input):
		print Input, Input.Tail

namespace metaboo

import Boo.OMeta
import Boo.PatternMatching
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.OMeta.Parser

def printTokens(text as string):
	printTokens BooParser(), text

def printTokens(grammar as OMetaGrammar, text as string):
	sep = "=" * 20
	print sep
	for token in scan(grammar, 'scanner', text):
		print token
	print sep

#print Tokenizer().indentation(" \n  foo")

printTokens """
class class0:

	class Bar:
		pass

	def foo():
		a = 3
		a = 4
"""

code = """
class Foo:
	def foo():
		a = 3
class Bar:
	class Baz:
		pass
	class Gazong:
		pass
"""
#printTokens code
#print BooParser().module(code)

code = """def foo():
	a = 3
	return bar(a)
"""
#printTokens code
match BooParser().method(code):
	case SuccessfulMatch(Input: OMetaInput(IsEmpty: true), Value: m=Method()):
		print m.ToCodeString()

code = """
class Foo:
def foo():
a = 3
return a
end
end
"""
#printTokens WSABooParser(), code
match WSABooParser().Apply('module', code):
	case SuccessfulMatch(Value: mod=Module()):
		print mod.ToCodeString()
	case FailedMatch(Input):
		print Input, Input.Tail


*.boo also matches *.booproj for some odd reason

namespace boojay

import System.IO
import Boo.Lang.Useful.CommandLine from Boo.Lang.Useful

class CommandLine(AbstractCommandLine):

	[getter(References)]
	_references = List[of string]()

	_sourceFiles = List[of string]()

	_srcDirs = List[of string]()

	def constructor(argv):
		Parse(argv)

	def SourceFiles():

		for srcFile as string in _sourceFiles:
			yield srcFile

		for srcDir in _srcDirs:
			for fname in Directory.GetFiles(srcDir, "*.boo"):
				continue unless fname.EndsWith("boo")
				yield fname

	IsValid:
		get: return len(self._sourceFiles) > 0 or len(self._srcDirs) > 0

	[Option("Output directory", ShortForm: "o", LongForm: "out")]
	public OutputDirectory = "."

	[Option("Prints the resulting bytecode to stdout.", ShortForm: 'p', LongForm: "print")]
	public PrintCode = false

	[Option("Prints the expanded boo code to stdout.", LongForm: "boo")]
	public Boo = false

	[Option("Enables duck typing.", LongForm: "ducky")]
	public Ducky = false

	[Option("Enables writing debug symbols.", LongForm: "debug")]
	public Debug = false

	[Option("Enables verbose mode.", LongForm: "verbose")]
	public Verbose = false

	[Option("Prints additional compiler internal messages to stdout.", LongForm: "debug-compiler")]
	public DebugCompiler = false

	[Option("References the specified {assembly}", ShortForm: 'r', LongForm: "reference", MaxOccurs: int.MaxValue)]
	def AddReference(reference as string):
		_references.AddUnique(reference)

	[Option("Includes all *.boo files from {srcdir}", LongForm: "srcdir", MaxOccurs: int.MaxValue)]
	def AddSourceDir(srcDir as string):
		_srcDirs.AddUnique(Path.GetFullPath(srcDir))

	[Option("display this help and exit", LongForm: "help")]
	public DoHelp = false

	[Argument]
	def AddSourceFile([required] sourceFile as string):
		_sourceFiles.Add(sourceFile)

namespace boojay

import System.IO
import Boo.Lang.Useful.CommandLine from Boo.Lang.Useful

class CommandLine(AbstractCommandLine):

	[getter(References)]
	_references = List[of string]()

	_sourceFiles = List[of string]()

	_srcDirs = List[of string]()

	def constructor(argv):
		Parse(argv)

	def SourceFiles():

		for srcFile as string in _sourceFiles:
			yield srcFile

		for srcDir in _srcDirs:
			for fname in Directory.GetFiles(srcDir, "*.boo"):
				yield fname

	IsValid:
		get: return len(self._sourceFiles) > 0 or len(self._srcDirs) > 0

	[Option("Output directory", ShortForm: "o", LongForm: "out")]
	public OutputDirectory = "."

	[Option("Prints the resulting bytecode to stdout.", ShortForm: 'p', LongForm: "print")]
	public PrintCode = false

	[Option("Prints the expanded boo code to stdout.", LongForm: "boo")]
	public Boo = false

	[Option("Enables duck typing.", LongForm: "ducky")]
	public Ducky = false

	[Option("Enables writing debug symbols.", LongForm: "debug")]
	public Debug = false

	[Option("Enables verbose mode.", LongForm: "verbose")]
	public Verbose = false

	[Option("Prints additional compiler internal messages to stdout.", LongForm: "debug-compiler")]
	public DebugCompiler = false

	[Option("References the specified {assembly}", ShortForm: 'r', LongForm: "reference", MaxOccurs: int.MaxValue)]
	def AddReference(reference as string):
		_references.AddUnique(reference)

	[Option("Includes all *.boo files from {srcdir}", LongForm: "srcdir", MaxOccurs: int.MaxValue)]
	def AddSourceDir(srcDir as string):
		_srcDirs.AddUnique(Path.GetFullPath(srcDir))

	[Option("display this help and exit", LongForm: "help")]
	public DoHelp = false

	[Argument]
	def AddSourceFile([required] sourceFile as string):
		_sourceFiles.Add(sourceFile)


show runtime version (1.1 or 2.0) in booish

git-svn-id: fcce7d6ce0ac15bf24f68871b5145d46fc068279@2095 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

import System
import System.Diagnostics
import Boo.Lang.Compiler.Steps
import Boo.Lang.Interpreter

interpreter = InteractiveInterpreter(RememberLastValue: true)

if "--print-modules" in argv:
	interpreter.Pipeline.Add(PrintBoo())

if "--debug" in argv:
	Debug.Listeners.Add(TextWriterTraceListener(Console.Out))

print """Welcome to booish, an interpreter for the boo programming language.

Running boo ${BooVersion} in CLR v${Environment.Version}.

The following builtin functions are available:
    dir(Type): lists the members of a type
    help(Type): prints detailed information about a type
    load(string): evals an external boo file
    globals(): returns the names of all variables known to the interpreter
	getRootNamespace(): namespace navigation

Enter boo code in the prompt below."""

interpreter.ConsoleLoopEval()

#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

import System
import System.Diagnostics
import Boo.Lang.Compiler.Steps
import Boo.Lang.Interpreter

interpreter = InteractiveInterpreter(RememberLastValue: true)

if "--print-modules" in argv:
	interpreter.Pipeline.Add(PrintBoo())

if "--debug" in argv:
	Debug.Listeners.Add(TextWriterTraceListener(Console.Out))

print """Welcome to booish, an interpreter for the boo programming language.

Running boo ${BooVersion}.

The following builtin functions are available:
    dir(Type): lists the members of a type
    help(Type): prints detailed information about a type
    load(string): evals an external boo file
    globals(): returns the names of all variables known to the interpreter
	getRootNamespace(): namespace navigation

Enter boo code in the prompt below."""

interpreter.ConsoleLoopEval()


fixed test

fixed test

"""
A STRING
"""

def producer() as string*:
	yield "a string"

def consume(strings as string*):
	enumerator = strings.iterator()
	try:
		while true:	print enumerator.next().toUpperCase()
	except:
		pass

consume producer()

"""
A STRING
"""

def producer() as string*:
	yield "a string"

def consume(strings as string*):
	enumerator = strings
	try:
		while true:	print enumerator.next().toUpperCase()
	except:
		pass

consume producer()


Support setTimeout in the fixture test runner

import NUnit.Framework

import System.IO(Path, Directory, StreamReader)
import System.Reflection(Assembly)
import System.Timers(Timer)

import Boo.Lang.Compiler.IO
import BooJs.Compiler

# The JavaScript interpretter
import Jurassic(ScriptEngine, JavaScriptException, CompatibilityMode)
import Jurassic.Library(ObjectInstance, FunctionInstance, JSFunctionAttribute)

class ConsoleMock(ObjectInstance):
    _output = []

    def constructor(engine as ScriptEngine):
        super(engine)
        PopulateFunctions()

    [JSFunction(Name:'log')]
    def log(*msg as (object)):
        _output.Add(join(msg, ' '))

    def output():
        return _output.Join("\n")

    def reset():
        _output.Clear()

static class Window:
    timers = List[of Timer]()

    def hasTimers():
        return len(timers) > 0

    def clearTimers():
        for timer in timers:
            timer.Stop()
        timers.Clear()

    def waitTimers():
        while hasTimers():
            System.Threading.Thread.Sleep(200)

    [JSFunction(Name:'setTimeout')]
    def setTimeout(callback as FunctionInstance, millisec as int) as int:
        timer = Timer(System.Math.Max(millisec, 1))
        timers.Add(timer)
        timer.AutoReset = false
        timer.Enabled = true
        timer.Elapsed += do:
            try:
                callback.Call(callback)
            ensure:
                timer.Stop()
                timers.Remove(timer)

        timer.Start()
        return -1

class FixtureRunner:

    static _comp as BooJsCompiler
    static _engine as ScriptEngine

    static _tests_path as string

    static def fixture_path(fname):
      if not _tests_path:
        # Find the path where the assembly resides
        path = Assembly.GetExecutingAssembly().CodeBase

        # Look for the tests directory in once of its parent paths
        while path = Path.GetFullPath(Path.Combine(path, '..')):
          if Directory.Exists(Path.Combine(path, 'tests')):
            _tests_path = path
            break
          elif path == Path.GetPathRoot(path):
            raise 'Unable to find tests directory'

      return Path.Combine(_tests_path, fname)

    static def run(file as string):
      file = fixture_path(file)

      timer = System.Diagnostics.Stopwatch()

      comp = setupCompiler()
      comp.Parameters.Ducky = false
      comp.Parameters.Strict = false

      # Enable compiler debug messages
      #comp.Parameters.TraceLevel = System.Diagnostics.TraceLevel.Verbose

      #print 'Setup: ', timer.ElapsedMilliseconds

      # Check if we want to ignore this fixture
      fp = StreamReader(file)
      while (line = fp.ReadLine()) != null:
        if line.IndexOf('#IGNORE') == 0:
          Assert.Ignore(line.Substring(len('#IGNORE')+1))
        elif line.IndexOf('#DUCKY') == 0:
          comp.Parameters.Ducky = true

      comp.Parameters.Input.Clear()
      comp.Parameters.Input.Add(FileInput(file))

      # Add the test runner assembly so we can resolve imports for supporting types
      comp.Parameters.References.Add(Assembly.GetExecutingAssembly())

      timer.Restart()

      result = comp.Run()

      #print 'Compilation: ', timer.ElapsedMilliseconds

      if len(result.Warnings):
        for warn as Boo.Lang.Compiler.CompilerWarning in result.Warnings:
            li = warn.LexicalInfo
            name = System.IO.Path.GetFileName(li.FileName)
            print "$(warn.Code) $(warn.Message) [$name:$(li.Line),$(li.Column)]"

      if len(result.Errors):
        for err as Boo.Lang.Compiler.CompilerError in result.Errors:
            li = err.LexicalInfo
            name = System.IO.Path.GetFileName(li.FileName)
            print "$(err.Code): $(err.Message) [$name:$(li.Line),$(li.Column)]"
        print '-----------------------------------------------------'
        print result.CompileUnit.ToCodeString()
        raise result.Errors[0]

      module = result.CompileUnit.Modules[0]
      expected = module.Documentation or ''

      code = comp.Parameters.OutputWriter.ToString()
      runTest(code, expected)

    static def setupCompiler():
        if not _comp:
            pipeline = Pipelines.PrintJs()
            #pipeline = Pipelines.PrintAst()
            #pipeline = Pipelines.PrintBoo()

            timer = System.Diagnostics.Stopwatch()
            pipeline.BeforeStep += def(pipeline, args):
                //print '-------------------------------------------'
                //print 'Step:', args.Step
                //print args.Context.CompileUnit
                timer.Restart()

            pipeline.AfterStep += def(pipeline, args):
                if timer.ElapsedMilliseconds > 100:
                    print 'Slow Step {0}: {1}ms' % (args.Step.GetType().Name, timer.ElapsedMilliseconds)

            _comp = newBooJsCompiler(pipeline)
            _comp.Parameters.Debug = true
            _comp.Parameters.GenerateInMemory = true

        # Reset the output writer
        _comp.Parameters.OutputWriter = System.IO.StringWriter()
        return _comp

    static def setupInterpreter():
        if not self._engine:
            self._engine = ScriptEngine()
            # Try to target older browser with ES3 (JS 1.5)
            self._engine.CompatibilityMode = CompatibilityMode.ECMAScript3
            # Force strict mode
            self._engine.ForceStrictMode = true

            # TODO: Does this help us somehow to get better error reports?
            #engine.EnableDebugging = true

            # Configure the global environment
            self._engine.SetGlobalFunction('setTimeout', Window.setTimeout)

            console = ConsoleMock(self._engine)
            self._engine.SetGlobalValue('console', console)

            # Load runtime
            stream = typeof(FixtureRunner).Assembly.GetManifestResourceStream('Boo.js')
            reader = System.IO.StreamReader(stream)
            self._engine.Execute(reader.ReadToEnd())

            # Patch the runtime to be compatible with Jurassic
            self._engine.Execute('Boo.AssertionError.prototype.toString = function(){ return this.message; };')

            # Load tests support types
            stream = typeof(FixtureRunner).Assembly.GetManifestResourceStream('BooJs.Tests.Support.js')
            reader = System.IO.StreamReader(stream)
            self._engine.Execute(reader.ReadToEnd())

            self._engine.ExecuteFile('/Users/drslump/www/boojs/src/Boo.Async.js')

        return self._engine

    static def runTest(code as string, expected as string):

        # TODO: Check if we can reuse the same engine
        using engine = setupInterpreter():

          console as ConsoleMock = engine.GetGlobalValue('console')
          console.reset()

          # Wrap code is a function to avoid leaking many globals
          #code = "(function(){\n\n" + code + "\n\n}).call(this)\n"

          try:
            engine.Execute(code)
            Window.waitTimers()

            Assert.AreEqual(expected, console.output())
          except ex:
            Window.clearTimers()

            jsex = ex as Jurassic.JavaScriptException
            if jsex:
                jsobj = jsex.ErrorObject as Jurassic.Library.ObjectInstance
                if jsobj and jsobj.HasProperty('boo_filename'):
                  print join(('Exception: "', ex.Message, '" at ',
                          jsobj.GetPropertyValue('boo_filename'), ':',
                          jsobj.GetPropertyValue('boo_line')
                      ), '')

            print '----------------------------------------------[code]-'
            print code.Trim()
            print '--------------------------------------------[output]-'
            print console.output()
            print '-----------------------------------------------------'

            raise

import NUnit.Framework

import System.IO(Path, Directory, StreamReader)
import System.Reflection(Assembly)

import Boo.Lang.Compiler.IO
import BooJs.Compiler

# The JavaScript interpretter
import Jurassic(ScriptEngine, JavaScriptException, CompatibilityMode)
import Jurassic.Library(ObjectInstance, JSFunctionAttribute)

class ConsoleMock(ObjectInstance):
    _output = []

    def constructor(engine as ScriptEngine):
        super(engine)
        PopulateFunctions()

    [JSFunction(Name:'log')]
    def log(*msg as (object)):
        _output.Add(join(msg, ' '))

    def output():
        return _output.Join("\n")

    def reset():
        _output.Clear()

class FixtureRunner:

    static _comp as BooJsCompiler
    static _engine as ScriptEngine

    static _tests_path as string

    static def fixture_path(fname):
      if not _tests_path:
        # Find the path where the assembly resides
        path = Assembly.GetExecutingAssembly().CodeBase

        # Look for the tests directory in once of its parent paths
        while path = Path.GetFullPath(Path.Combine(path, '..')):
          if Directory.Exists(Path.Combine(path, 'tests')):
            _tests_path = path
            break
          elif path == Path.GetPathRoot(path):
            raise 'Unable to find tests directory'

      return Path.Combine(_tests_path, fname)

    static def run(file as string):
      file = fixture_path(file)

      timer = System.Diagnostics.Stopwatch()

      comp = setupCompiler()
      comp.Parameters.Ducky = false
      comp.Parameters.Strict = false

      # Enable compiler debug messages
      #comp.Parameters.TraceLevel = System.Diagnostics.TraceLevel.Verbose

      #print 'Setup: ', timer.ElapsedMilliseconds

      # Check if we want to ignore this fixture
      fp = StreamReader(file)
      while (line = fp.ReadLine()) != null:
        if line.IndexOf('#IGNORE') == 0:
          Assert.Ignore(line.Substring(len('#IGNORE')+1))
        elif line.IndexOf('#DUCKY') == 0:
          comp.Parameters.Ducky = true

      comp.Parameters.Input.Clear()
      comp.Parameters.Input.Add(FileInput(file))

      # Add the test runner assembly so we can resolve imports for supporting types
      comp.Parameters.References.Add(Assembly.GetExecutingAssembly())

      timer.Restart()

      result = comp.Run()

      #print 'Compilation: ', timer.ElapsedMilliseconds

      if len(result.Warnings):
        for warn as Boo.Lang.Compiler.CompilerWarning in result.Warnings:
            li = warn.LexicalInfo
            name = System.IO.Path.GetFileName(li.FileName)
            print "$(warn.Code) $(warn.Message) [$name:$(li.Line),$(li.Column)]"

      if len(result.Errors):
        for err as Boo.Lang.Compiler.CompilerError in result.Errors:
            li = err.LexicalInfo
            name = System.IO.Path.GetFileName(li.FileName)
            print "$(err.Code): $(err.Message) [$name:$(li.Line),$(li.Column)]"
        print '-----------------------------------------------------'
        print result.CompileUnit.ToCodeString()
        raise result.Errors[0]

      module = result.CompileUnit.Modules[0]
      expected = module.Documentation or ''

      code = comp.Parameters.OutputWriter.ToString()
      runTest(code, expected)

    static def setupCompiler():
        if not _comp:
            pipeline = Pipelines.PrintJs()
            #pipeline = Pipelines.PrintAst()
            #pipeline = Pipelines.PrintBoo()

            timer = System.Diagnostics.Stopwatch()
            pipeline.BeforeStep += def(pipeline, args):
                //print '-------------------------------------------'
                //print 'Step:', args.Step
                //print args.Context.CompileUnit
                timer.Restart()

            pipeline.AfterStep += def(pipeline, args):
                if timer.ElapsedMilliseconds > 100:
                    print 'Slow Step {0}: {1}ms' % (args.Step.GetType().Name, timer.ElapsedMilliseconds)

            _comp = newBooJsCompiler(pipeline)
            _comp.Parameters.Debug = true
            _comp.Parameters.GenerateInMemory = true

        # Reset the output writer
        _comp.Parameters.OutputWriter = System.IO.StringWriter()
        return _comp

    static def setupInterpreter():
        if not self._engine:
            self._engine = ScriptEngine()
            # Try to target older browser with ES3 (JS 1.5)
            self._engine.CompatibilityMode = CompatibilityMode.ECMAScript3
            # Force strict mode
            self._engine.ForceStrictMode = true

            # TODO: Does this help us somehow to get better error reports?
            #engine.EnableDebugging = true

            # Configure the global environment
            console = ConsoleMock(self._engine)
            self._engine.SetGlobalValue('console', console)

            # Load runtime
            stream = typeof(FixtureRunner).Assembly.GetManifestResourceStream('Boo.js')
            reader = System.IO.StreamReader(stream)
            self._engine.Execute(reader.ReadToEnd())

            # Patch the runtime to be compatible with Jurassic
            self._engine.Execute('Boo.AssertionError.prototype.toString = function(){ return this.message; };')

            # Load tests support types
            stream = typeof(FixtureRunner).Assembly.GetManifestResourceStream('BooJs.Tests.Support.js')
            reader = System.IO.StreamReader(stream)
            self._engine.Execute(reader.ReadToEnd())

        return self._engine

    static def runTest(code as string, expected as string):

        # TODO: Check if we can reuse the same engine
        using engine = setupInterpreter():

          console as ConsoleMock = engine.GetGlobalValue('console')
          console.reset()

          # Wrap code is a function to avoid leaking many globals
          #code = "(function(){\n\n" + code + "\n\n}).call(this)\n"

          try:
            engine.Execute(code)
            Assert.AreEqual(expected, console.output())
          except ex:
            jsex = ex as Jurassic.JavaScriptException
            if jsex:
                jsobj = jsex.ErrorObject as Jurassic.Library.ObjectInstance
                if jsobj and jsobj.HasProperty('boo_filename'):
                  print join(('Exception: "', ex.Message, '" at ',
                          jsobj.GetPropertyValue('boo_filename'), ':',
                          jsobj.GetPropertyValue('boo_line')
                      ), '')

            print '----------------------------------------------[code]-'
            print code.Trim()
            print '--------------------------------------------[output]-'
            print console.output()
            print '-----------------------------------------------------'

            raise


Removed unnecessary file

Removed unnecessary file

git-svn-id: bab0c2de90ee11a20376049c2cdee62584491f34@1701 73e77b4c-caa6-f847-a29a-24ab75ae54b6


better test case for array equality

better test case for array equality

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

a1 as object = (1, 2)
a2 as object = (1, 2)
assert a1 == a2

a3 as object = ((1, 2), (3, 4))
a4 as object = ((1, 2), (3, 4))
assert a3 == a4


booish: read/eval/loop

booish: read/eval/loop

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

namespace booish

import Boo.Lang
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.IO

class InterpreterEntity(ITypedEntity):

	[getter(Name)]
	[getter(FullName)]
	_name as string

	[getter(Type)]
	_type as IType

	def constructor(name, type):
		_name = name
		_type = type

	EntityType:
		get:
			return TypeSystem.EntityType.Custom

	static def IsInterpreterEntity(node as Node):
		return node.Entity is not null and TypeSystem.EntityType.Custom == node.Entity.EntityType

class InterpreterNamespace(INamespace):

	[getter(ParentNamespace)]
	_parent as INamespace

	_tss as TypeSystemServices

	_interpreter as InteractiveInterpreter

	_declarations = {}

	def constructor(interpreter, tss, parent):
		_interpreter = interpreter
		_tss = tss
		_parent = parent

	def Declare(name as string, type as IType):
		_declarations.Add(name, entity=InterpreterEntity(name, type))
		return entity

	def Resolve(targetList as List, name as string, flags as EntityType) as bool:
		return false unless flags == EntityType.Any

		entity as IEntity = _declarations[name]
		if entity is null:
			value = _interpreter.GetValue(name)
			if value is not null:
				entity = Declare(name, _tss.Map(value.GetType()))

		if entity is not null:
			targetList.Add(entity)
			return true

		return false

	def GetMembers():
		return array(IEntity, 0)

class ProcessVariableDeclarations(Steps.ProcessMethodBodiesWithDuckTyping):

	_namespace as InterpreterNamespace
	_interpreter as InteractiveInterpreter

	def constructor(interpreter):
		_interpreter = interpreter

	override def Initialize(context as CompilerContext):
		super(context)

		_namespace = InterpreterNamespace(
							_interpreter,
							TypeSystemServices,
							NameResolutionService.GlobalNamespace)
		NameResolutionService.GlobalNamespace = _namespace

	override def ProcessAssignment(node as BinaryExpression):
		# prevent 'Expression can't be assigned to' error
		super(node) unless InterpreterEntity.IsInterpreterEntity(node.Left)

	override def DeclareLocal(name as string, type as IType, privateScope as bool):
		return super(name, type, privateScope) if privateScope
		return _namespace.Declare(name, type)

class ProcessInterpreterReferences(Steps.AbstractTransformerCompilerStep):

	static InteractiveInterpreter_GetValue = typeof(InteractiveInterpreter).GetMethod("GetValue")
	static InteractiveInterpreter_SetValue = typeof(InteractiveInterpreter).GetMethod("SetValue")

	_interpreterField as Field
	_namespace as InterpreterNamespace
	_interpreter as InteractiveInterpreter

	def constructor(interpreter):
		_interpreter = interpreter

	override def Run():
		Visit(CompileUnit) if 0 == len(Errors)

	override def OnModule(node as Module):

		module = cast(ModuleEntity, node.Entity).ModuleClass
		return unless module

		_interpreterField = CodeBuilder.CreateField("ParentInterpreter", TypeSystemServices.Map(InteractiveInterpreter))
		_interpreterField.Modifiers = TypeMemberModifiers.Public | TypeMemberModifiers.Static
		module.Members.Add(_interpreterField)

		super(node)

	override def OnReferenceExpression(node as ReferenceExpression):
		super(node)
		return unless InterpreterEntity.IsInterpreterEntity(node) and not AstUtil.IsLhsOfAssignment(node)

		ReplaceCurrentNode(CreateGetValue(node))

	override def LeaveBinaryExpression(node as BinaryExpression):
		if InterpreterEntity.IsInterpreterEntity(node.Left):
			ReplaceCurrentNode(CreateSetValue(node))

	def CreateGetValue(node as ReferenceExpression):
		return CodeBuilder.CreateCast(
				node.ExpressionType,
				CodeBuilder.CreateMethodInvocation(
					CodeBuilder.CreateReference(_interpreterField),
					TypeSystemServices.Map(InteractiveInterpreter_GetValue),
					CodeBuilder.CreateStringLiteral(node.Name)))

	def CreateSetValue(node as BinaryExpression):
		return CodeBuilder.CreateMethodInvocation(
					CodeBuilder.CreateReference(_interpreterField),
					TypeSystemServices.Map(InteractiveInterpreter_SetValue),
					CodeBuilder.CreateStringLiteral(cast(ReferenceExpression, node.Left).Name),
					node.Right)

class InteractiveInterpreter:

	_compiler = BooCompiler()

	_values = {}

	def constructor():
		pipeline = Pipelines.CompileToMemory()
		index = pipeline.Find(Steps.ProcessMethodBodiesWithDuckTyping)
		pipeline[index] = ProcessVariableDeclarations(self)
		pipeline.InsertBefore(Steps.EmitAssembly, ProcessInterpreterReferences(self))
		//pipeline.Add(Steps.PrintBoo())

		_compiler.Parameters.Pipeline = pipeline

	def Eval(code as string):
		_compiler.Parameters.Input.Clear()
		_compiler.Parameters.Input.Add(StringInput("src", code))

		result = _compiler.Run()
		if 0 == len(result.Errors):
			entry = result.GeneratedAssemblyEntryPoint
			entry.DeclaringType.GetField("ParentInterpreter").SetValue(null, self)
			entry.Invoke(null, (null,))
		return result

	def SetValue(name as string, value):
		_values[name] = value

	def GetValue(name as string):
		return _values[name]
/*
interpreter = InteractiveInterpreter()
interpreter.SetValue("name", "boo")
interpreter.SetValue("age", 3)

interpreter.Eval("""
print(name)
print(age)
age += 1
""")

assert 4 == interpreter.GetValue("age")

interpreter.Eval("age = 42")
assert 42 == interpreter.GetValue("age")

interpreter.Eval("""
value = 3
print(value*2)
""")

assert 3 == interpreter.GetValue("value")

interpreter.Eval("x2 = { v as int | return v*2 }")

x2 as callable = interpreter.GetValue("x2")
assert 4 == x2(2)

interpreter.Eval("e = i*2 for i in range(value)")
assert array(interpreter.GetValue("e")) == (0, 2, 4)

# let's loop
interpreter.Eval("""
for i in range(3):
	print(i*2)
""")
print("i: ${interpreter.GetValue('i')}")
*/

interpreter = InteractiveInterpreter()
while line=prompt(">>> "):
	result = interpreter.Eval(line)
	for error in result.Errors:
		print("ERROR: ${error.Message}")

namespace booish

import Boo.Lang
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.IO

class InterpreterEntity(ITypedEntity):

	[getter(Name)]
	[getter(FullName)]
	_name as string

	[getter(Type)]
	_type as IType

	def constructor(name, type):
		_name = name
		_type = type

	EntityType:
		get:
			return TypeSystem.EntityType.Custom

	static def IsInterpreterEntity(node as Node):
		return node.Entity is not null and TypeSystem.EntityType.Custom == node.Entity.EntityType

class InterpreterNamespace(INamespace):

	[getter(ParentNamespace)]
	_parent as INamespace

	_tss as TypeSystemServices

	_interpreter as InteractiveInterpreter

	_declarations = {}

	def constructor(interpreter, tss, parent):
		_interpreter = interpreter
		_tss = tss
		_parent = parent

	def Declare(name as string, type as IType):
		_declarations.Add(name, entity=InterpreterEntity(name, type))
		return entity

	def Resolve(targetList as List, name as string, flags as EntityType) as bool:
		return false unless flags == EntityType.Any

		entity as IEntity = _declarations[name]
		if entity is null:
			value = _interpreter.GetValue(name)
			if value is not null:
				entity = Declare(name, _tss.Map(value.GetType()))

		if entity is not null:
			targetList.Add(entity)
			return true

		return false

	def GetMembers():
		return array(IEntity, 0)

class ProcessVariableDeclarations(Steps.ProcessMethodBodiesWithDuckTyping):

	_namespace as InterpreterNamespace
	_interpreter as InteractiveInterpreter

	def constructor(interpreter):
		_interpreter = interpreter

	override def Initialize(context as CompilerContext):
		super(context)

		_namespace = InterpreterNamespace(
							_interpreter,
							TypeSystemServices,
							NameResolutionService.GlobalNamespace)
		NameResolutionService.GlobalNamespace = _namespace

	override def ProcessAssignment(node as BinaryExpression):
		# prevent 'Expression can't be assigned to' error
		super(node) unless InterpreterEntity.IsInterpreterEntity(node.Left)

	override def DeclareLocal(name as string, type as IType, privateScope as bool):
		return super(name, type, privateScope) if privateScope
		return _namespace.Declare(name, type)

class ProcessInterpreterReferences(Steps.AbstractTransformerCompilerStep):

	static InteractiveInterpreter_GetValue = typeof(InteractiveInterpreter).GetMethod("GetValue")
	static InteractiveInterpreter_SetValue = typeof(InteractiveInterpreter).GetMethod("SetValue")

	_interpreterField as Field
	_namespace as InterpreterNamespace
	_interpreter as InteractiveInterpreter

	def constructor(interpreter):
		_interpreter = interpreter

	override def Run():
		Visit(CompileUnit) if 0 == len(Errors)

	override def OnModule(node as Module):

		module = cast(ModuleEntity, node.Entity).ModuleClass
		return unless module

		_interpreterField = CodeBuilder.CreateField("ParentInterpreter", TypeSystemServices.Map(InteractiveInterpreter))
		_interpreterField.Modifiers = TypeMemberModifiers.Public | TypeMemberModifiers.Static
		module.Members.Add(_interpreterField)

		super(node)

	override def OnReferenceExpression(node as ReferenceExpression):
		super(node)
		return unless InterpreterEntity.IsInterpreterEntity(node) and not AstUtil.IsLhsOfAssignment(node)

		ReplaceCurrentNode(CreateGetValue(node))

	override def LeaveBinaryExpression(node as BinaryExpression):
		if InterpreterEntity.IsInterpreterEntity(node.Left):
			ReplaceCurrentNode(CreateSetValue(node))

	def CreateGetValue(node as ReferenceExpression):
		return CodeBuilder.CreateCast(
				node.ExpressionType,
				CodeBuilder.CreateMethodInvocation(
					CodeBuilder.CreateReference(_interpreterField),
					TypeSystemServices.Map(InteractiveInterpreter_GetValue),
					CodeBuilder.CreateStringLiteral(node.Name)))

	def CreateSetValue(node as BinaryExpression):
		return CodeBuilder.CreateMethodInvocation(
					CodeBuilder.CreateReference(_interpreterField),
					TypeSystemServices.Map(InteractiveInterpreter_SetValue),
					CodeBuilder.CreateStringLiteral(cast(ReferenceExpression, node.Left).Name),
					node.Right)

class InteractiveInterpreter:

	_compiler = BooCompiler()

	_values = {}

	def constructor():
		pipeline = Pipelines.CompileToMemory()
		index = pipeline.Find(Steps.ProcessMethodBodiesWithDuckTyping)
		pipeline[index] = ProcessVariableDeclarations(self)
		pipeline.InsertBefore(Steps.EmitAssembly, ProcessInterpreterReferences(self))
		//pipeline.Add(Steps.PrintBoo())

		_compiler.Parameters.Pipeline = pipeline

	def Eval(code as string):
		_compiler.Parameters.Input.Clear()
		_compiler.Parameters.Input.Add(StringInput("src", code))

		result = _compiler.Run()
		assert 0 == len(result.Errors), "\n" + result.Errors.ToString(true)

		entry = result.GeneratedAssemblyEntryPoint
		entry.DeclaringType.GetField("ParentInterpreter").SetValue(null, self)
		entry.Invoke(null, (null,))

	def SetValue(name as string, value):
		_values[name] = value

	def GetValue(name as string):
		return _values[name]

interpreter = InteractiveInterpreter()
interpreter.SetValue("name", "boo")
interpreter.SetValue("age", 3)

interpreter.Eval("""
print(name)
print(age)
age += 1
""")

assert 4 == interpreter.GetValue("age")

interpreter.Eval("age = 42")
assert 42 == interpreter.GetValue("age")

interpreter.Eval("""
value = 3
print(value*2)
""")

assert 3 == interpreter.GetValue("value")

interpreter.Eval("x2 = { v as int | return v*2 }")

x2 as callable = interpreter.GetValue("x2")
assert 4 == x2(2)

interpreter.Eval("e = i*2 for i in range(value)")
assert array(interpreter.GetValue("e")) == (0, 2, 4)

# let's loop
interpreter.Eval("""
for i in range(3):
	print(i*2)
""")
print("i: ${interpreter.GetValue('i')}")


better status splitting (also applicable to 'svnlook changed')

git-svn-id: fcce7d6ce0ac15bf24f68871b5145d46fc068279@2585 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

"""
svn utility functions
"""
import System
import System.IO

class ResourceStatus:
	static def parse(line as string):
		parts = /\s+/.Split(line.Trim(), 2)
		return ResourceStatus(code: parts[0], resource: parts[1])

	public code as string
	public resource as string

	override def ToString():
		return "${code}\t${resource}"

def svn_status(resource as string):
	return parse_status(shell("svn", "status ${resource}"))

def parse_status(status as string):
	for line in lines(status):
		yield ResourceStatus.parse(line)

def svn_pg(resource as string, propertyName as string):
	return shell("svn", "pg ${propertyName} ${resource}")

def svn_ps(resource as string, propertyName as string, propertyValue as string):
	tempFile = ".svn_ignore"
	File.WriteAllText(tempFile, propertyValue)
	try:
		return shell("svn", "ps ${propertyName} --file \"${tempFile}\" ${resource}")
	ensure:
		File.Delete(tempFile)

def svn_locals(resource as string):
	return (
		status.resource
		for status in svn_status(resource)
		if status.code == "?")

def svn_ignore(resource as string, whatToIgnore as string):
	current = svn_pg(resource, "svn:ignore")
	print svn_ps(resource, "svn:ignore", current.Trim() + "\n" + whatToIgnore)

def lines(s as string):
	return line.Trim() for line in /(\r?\n)+/.Split(s) if len(line.Trim())

def confirm(message as string):
	return "y" == prompt("${message} (y/n): ")

#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

"""
svn utility functions
"""
import System
import System.IO

class ResourceStatus:
	public code as string
	public resource as string

def svn_status(resource as string):
	for line in lines(shell("svn", "status ${resource}")):
		yield ResourceStatus(code: line[:7].Trim(), resource: line[7:])

def svn_pg(resource as string, propertyName as string):
	return shell("svn", "pg ${propertyName} ${resource}")

def svn_ps(resource as string, propertyName as string, propertyValue as string):
	tempFile = ".svn_ignore"
	File.WriteAllText(tempFile, propertyValue)
	try:
		return shell("svn", "ps ${propertyName} --file \"${tempFile}\" ${resource}")
	ensure:
		File.Delete(tempFile)

def svn_locals(resource as string):
	return (
		status.resource
		for status in svn_status(resource)
		if status.code == "?")

def svn_ignore(resource as string, whatToIgnore as string):
	current = svn_pg(resource, "svn:ignore")
	print svn_ps(resource, "svn:ignore", current.Trim() + "\n" + whatToIgnore)

def lines(s as string):
	return line.Trim() for line in /(\r?\n)+/.Split(s) if len(line.Trim())

def confirm(message as string):
	return "y" == prompt("${message} (y/n): ")


revert failed attempt at rationalization and mark it TODO for later

git-svn-id: fcce7d6ce0ac15bf24f68871b5145d46fc068279@2520 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

namespace Boo.NAnt

import System
import System.Text
import System.Diagnostics
import System.IO
import NAnt.Core
import NAnt.Core.Attributes
import NAnt.Core.Types
import Boo.Lang.Compiler

abstract class AbstractBooTask(Task):

	_references = FileSet()

	_packages = OptionCollection()

	_pipeline as string

	[BuildElement("references")]
	References:
		get:
			return _references
		set:
			_references = value

	[BuildElementCollection("pkg-references", "package")]
	Packages:
		get:
			return _packages
		set:
			_packages = value

	[TaskAttribute("pipeline")]
	Pipeline:
		get:
			return _pipeline
		set:
			_pipeline = value

	protected def RunCompiler(compiler as BooCompiler):
		AddReferences(compiler.Parameters)
		AddPackages(compiler.Parameters)
		if _pipeline:
			compiler.Parameters.Pipeline = CompilerPipeline.GetPipeline(_pipeline)
		else:
			compiler.Parameters.Pipeline = GetDefaultPipeline()
		result = compiler.Run()
		CheckCompilationResult(result)
		return result

	protected def AddReferences(parameters as CompilerParameters):
		if _references.BaseDirectory is not null:
			baseDir = _references.BaseDirectory.ToString()
		else:
			baseDir = Project.BaseDirectory

		for reference as string in _references.Includes:
			path = reference
			if not Path.IsPathRooted(path):
				path = Path.Combine(baseDir, reference)
				if not File.Exists(path):
					print("${path} doesn't exist.")
					asm = Reflection.Assembly.LoadWithPartialName(Path.GetFileNameWithoutExtension(reference))
				else:
					asm = Reflection.Assembly.LoadFrom(path)
			else:
				asm = Reflection.Assembly.LoadFrom(path)

			print("reference: ${path}")
			try:
				parameters.References.Add(asm)
				//TODO: rationalize above call to parameters.References.Add(parameters.LoadAssembly(reference)) ?
				//      move basedir into CompilerParameters ?
			except x:
				raise BuildException(
					Boo.Lang.ResourceManager.Format("BCE0041", reference),
					Location,
					x)

	protected def AddPackages(parameters as CompilerParameters):
		for package as string in _packages:
			try:
				parameters.LoadReferencesFromPackage(package);
			except x:
				raise BuildException(
					Boo.Lang.ResourceManager.Format("BCE0041", package),
					Location,
					x)

	protected def CheckCompilationResult(context as CompilerContext):
		errors = context.Errors
		verbose = context.Parameters.TraceSwitch.TraceInfo
		for error in errors:
			LogError(error.ToString(verbose))
		for warning in context.Warnings:
			LogWarning(warning.ToString());

		if len(errors):
			LogInfo("${len(errors)} error(s).")
			raise BuildException("boo compilation error", Location)

	abstract def GetDefaultPipeline() as CompilerPipeline:
		pass

	def GetFrameworkDirectory():
		return Project.TargetFramework.FrameworkAssemblyDirectory.ToString()

	def print(message):
		LogVerbose(message)

	def LogInfo(message):
		self.Log(Level.Info, "${message}")

	def LogVerbose(message):
		self.Log(Level.Verbose, "${message}")

	def LogWarning(message):
		self.Log(Level.Warning, "${message}")

	def LogError(message):
		self.Log(Level.Error, "${message}")

def read(fname as string):
	using reader=File.OpenText(fname):
		return reader.ReadToEnd()

def write(fname as string, contents as string):
	using writer=StreamWriter(fname, false, System.Text.Encoding.UTF8):
		writer.Write(contents)

#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

namespace Boo.NAnt

import System
import System.Text
import System.Diagnostics
import System.IO
import NAnt.Core
import NAnt.Core.Attributes
import NAnt.Core.Types
import Boo.Lang.Compiler

abstract class AbstractBooTask(Task):

	_references = FileSet()

	_packages = OptionCollection()

	_pipeline as string

	[BuildElement("references")]
	References:
		get:
			return _references
		set:
			_references = value

	[BuildElementCollection("pkg-references", "package")]
	Packages:
		get:
			return _packages
		set:
			_packages = value

	[TaskAttribute("pipeline")]
	Pipeline:
		get:
			return _pipeline
		set:
			_pipeline = value

	protected def RunCompiler(compiler as BooCompiler):
		AddReferences(compiler.Parameters)
		AddPackages(compiler.Parameters)
		if _pipeline:
			compiler.Parameters.Pipeline = CompilerPipeline.GetPipeline(_pipeline)
		else:
			compiler.Parameters.Pipeline = GetDefaultPipeline()
		result = compiler.Run()
		CheckCompilationResult(result)
		return result

	protected def AddReferences(parameters as CompilerParameters):
		if _references.BaseDirectory is not null:
			baseDir = _references.BaseDirectory.ToString()
		else:
			baseDir = Project.BaseDirectory

		for reference as string in _references.Includes:
			print("reference: ${reference}")
			try:
				parameters.References.Add(parameters.LoadAssembly(reference))
			except x:
				raise BuildException(
					Boo.Lang.ResourceManager.Format("BCE0041", reference),
					Location,
					x)

	protected def AddPackages(parameters as CompilerParameters):
		for package as string in _packages:
			try:
				parameters.LoadReferencesFromPackage(package);
			except x:
				raise BuildException(
					Boo.Lang.ResourceManager.Format("BCE0041", package),
					Location,
					x)

	protected def CheckCompilationResult(context as CompilerContext):
		errors = context.Errors
		verbose = context.Parameters.TraceSwitch.TraceInfo
		for error in errors:
			LogError(error.ToString(verbose))
		for warning in context.Warnings:
			LogWarning(warning.ToString());

		if len(errors):
			LogInfo("${len(errors)} error(s).")
			raise BuildException("boo compilation error", Location)

	abstract def GetDefaultPipeline() as CompilerPipeline:
		pass

	def GetFrameworkDirectory():
		return Project.TargetFramework.FrameworkAssemblyDirectory.ToString()

	def print(message):
		LogVerbose(message)

	def LogInfo(message):
		self.Log(Level.Info, "${message}")

	def LogVerbose(message):
		self.Log(Level.Verbose, "${message}")

	def LogWarning(message):
		self.Log(Level.Warning, "${message}")

	def LogError(message):
		self.Log(Level.Error, "${message}")

def read(fname as string):
	using reader=File.OpenText(fname):
		return reader.ReadToEnd()

def write(fname as string, contents as string):
	using writer=StreamWriter(fname, false, System.Text.Encoding.UTF8):
		writer.Write(contents)