trace listeners are no longer used

trace listeners are no longer used

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 Main(argv as (string)):
	print "boojay .0a"

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

	compiler = newBoojayCompiler(selectPipeline(cmdLine))
	configureParams(cmdLine, compiler.Parameters)
	result = compiler.Run()
	showErrorsWarnings(cmdLine, result)
	outputJarFile(cmdLine, compiler.Parameters.OutputAssembly, result)
	return len(result.Errors)

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):

	if cmdLine.Verbose:
		params.TraceLevel = System.Diagnostics.TraceLevel.Verbose

	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)

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:]

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 Main(argv as (string)):
	print "boojay .0a"

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

	compiler = newBoojayCompiler(selectPipeline(cmdLine))
	configureParams(cmdLine, compiler.Parameters)
	result = compiler.Run()
	showErrorsWarnings(cmdLine, result)
	outputJarFile(cmdLine, compiler.Parameters.OutputAssembly, result)
	return len(result.Errors)

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:]


minor things

minor things

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

#region Licence

// Copyright (c) 2005, Sorin Ionescu (sorin.ionescu@gmail.com)
// 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 Sorin Ionescu 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.Examples.Attributes

import System;
import System.Runtime.Remoting.Messaging
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps

class AsyncAttribute(AbstractAstAttribute):
"""
Adds asynchronous helpers Begin<Method>/End<Method>
for a method.
"""
	_method          as Method
	_accessModifiers as TypeMemberModifiers

	override def Apply(node as Node):
		assert node isa Method

		_method = node

		if _method.IsProtected and _method.IsInternal:
			_accessModifiers = TypeMemberModifiers.Protected
			_accessModifiers = _accessModifiers | TypeMemberModifiers.Internal

		elif _method.IsPublic:
			_accessModifiers = TypeMemberModifiers.Public

		elif _method.IsProtected:
			_accessModifiers = TypeMemberModifiers.Protected

		elif _method.IsInternal:
			_accessModifiers = TypeMemberModifiers.Internal

		elif _method.IsPrivate:
			_accessModifiers = TypeMemberModifiers.Private

		EmitBeginMethod()
		EmitEndMethod()

	private def EmitBeginMethod():
		beginMethod = Method(
						_method.LexicalInfo,
						Name: "Begin" + _method.Name,
						Modifiers: _accessModifiers,
						ReturnType: CodeBuilder.CreateTypeReference(typeof(IAsyncResult)))
		beginMethod.Parameters.ExtendWithClones(_method.Parameters)
		beginMethod.Parameters.Add(
				ParameterDeclaration(
					"callback",
					CodeBuilder.CreateTypeReference(typeof(AsyncCallback))))
		beginMethod.Parameters.Add(
				ParameterDeclaration(
					"state",
					CodeBuilder.CreateTypeReference(typeof(object))))

		asyncInvocation = MethodInvocationExpression(
							Target: MemberReferenceExpression(
										ReferenceExpression(_method.Name),
										"BeginInvoke"))
		for parameter in beginMethod.Parameters:
			asyncInvocation.Arguments.Add(
					ReferenceExpression(parameter.Name))

		beginMethod.Body.Add(ReturnStatement(asyncInvocation))
		_method.DeclaringType.Members.Add(beginMethod)

	private def EmitEndMethod():
		endMethod = Method(
						_method.LexicalInfo,
						Name: "End" + _method.Name,
						Modifiers: _accessModifiers)
		endMethod.Parameters.Add(
			ParameterDeclaration(
				"result",
				CodeBuilder.CreateTypeReference(typeof(IAsyncResult))))

		asyncInvocation = MethodInvocationExpression(
							Target: MemberReferenceExpression(
										ReferenceExpression(_method.Name),
										"EndInvoke"))
		asyncInvocation.Arguments.Add(ReferenceExpression("result"))
		endMethod.Body.Add(ReturnStatement(asyncInvocation))

		_method.DeclaringType.Members.Add(endMethod)

		# cache the voidType reference because we are going
		# to lose the context after this method returns
		# (see AbstractCompilerComponent.Dispose)
		voidType = Context.TypeSystemServices.VoidType
		Context.Parameters.Pipeline.AfterStep += def (sender, e as CompilerStepEventArgs):
			if e.Step isa ProcessMethodBodies:
				if _method.ReturnType.Entity is voidType:
					returnStatement = endMethod.Body.Statements[-1] as ReturnStatement
					endMethod.Body.Statements.Replace(
							returnStatement,
							ExpressionStatement(returnStatement.Expression))

#region Licence

// Copyright (c) 2005, Sorin Ionescu (sorin.ionescu@gmail.com)
// 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 Sorin Ionescu 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.Examples.Attributes

import System;
import System.Runtime.Remoting.Messaging
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps

class AsyncAttribute(AbstractAstAttribute):
"""
Adds asynchronous helpers Begin<Method>/End<Method>
for a method.
"""
	_method          as Method
	_accessModifiers as TypeMemberModifiers

	override def Apply(node as Node):
		assert node isa Method

		_method = node

		if _method.IsProtected and _method.IsInternal:
			_accessModifiers = TypeMemberModifiers.Protected
			_accessModifiers = _accessModifiers | TypeMemberModifiers.Internal

		elif _method.IsPublic:
			_accessModifiers = TypeMemberModifiers.Public

		elif _method.IsProtected:
			_accessModifiers = TypeMemberModifiers.Protected

		elif _method.IsInternal:
			_accessModifiers = TypeMemberModifiers.Internal

		elif _method.IsPrivate:
			_accessModifiers = TypeMemberModifiers.Private

		EmitBeginMethod()
		EmitEndMethod()

	private def EmitBeginMethod():
		beginMethod = Method(
						_method.LexicalInfo,
						Name: "Begin" + _method.Name,
						Modifiers: _accessModifiers,
						ReturnType: CodeBuilder.CreateTypeReference(typeof(IAsyncResult)))
		beginMethod.Parameters.ExtendWithClones(_method.Parameters)
		beginMethod.Parameters.Add(
				ParameterDeclaration(
					"callback",
					CodeBuilder.CreateTypeReference(typeof(AsyncCallback))))
		beginMethod.Parameters.Add(
				ParameterDeclaration(
					"state",
					CodeBuilder.CreateTypeReference(typeof(object))))

		asyncInvocation = MethodInvocationExpression(
							Target: MemberReferenceExpression(
										ReferenceExpression(_method.Name),
										"BeginInvoke"))
		for parameter in beginMethod.Parameters:
			asyncInvocation.Arguments.Add(
					ReferenceExpression(parameter.Name))

		beginMethod.Body.Add(ReturnStatement(asyncInvocation))
		_method.DeclaringType.Members.Add(beginMethod)

	private def EmitEndMethod():
		endMethod = Method(
						_method.LexicalInfo,
						Name: "End" + _method.Name,
						Modifiers: _accessModifiers)
		endMethod.Parameters.Add(
			ParameterDeclaration(
				"result",
				CodeBuilder.CreateTypeReference(typeof(IAsyncResult))))

		asyncInvocation = MethodInvocationExpression(
							Target: MemberReferenceExpression(
										ReferenceExpression(_method.Name),
										"EndInvoke"))
		asyncInvocation.Arguments.Add(ReferenceExpression("result"))
		endMethod.Body.Add(ReturnStatement(asyncInvocation))

		_method.DeclaringType.Members.Add(endMethod)

		# cache the voidType reference because we are going
		# to loose the context after this method returns
		# (see AbstractCompilerComponent.Dispose)
		voidType = Context.TypeSystemServices.VoidType
		Context.Parameters.Pipeline.AfterStep += def (sender as object, e as CompilerStepEventArgs):
			if e.Step isa ProcessMethodBodies:
				if _method.ReturnType.Entity is voidType:
					returnStatement = endMethod.Body.Statements[-1] as ReturnStatement
					endMethod.Body.Statements.Replace(
							returnStatement,
							ExpressionStatement(returnStatement.Expression))


Moved week classes

Moved week classes

Tweaked NuGet and build scripts

import System.IO

project_name  = "NExtra"
assembly_file = "SharedAssemblyInfo.cs"

build_folder  = "_tmpbuild_/"
build_version = ""
build_config  = env('config')

test_assemblies = (
   "${project_name}.Tests/bin/${build_config}/${project_name}.Tests.dll",
   "${project_name}.Web.Tests/bin/${build_config}/${project_name}.Web.Tests.dll",
   "${project_name}.Mvc.Tests/bin/${build_config}/${project_name}.Mvc.Tests.dll",
   "${project_name}.WPF.Tests/bin/${build_config}/${project_name}.WPF.Tests.dll",
   "${project_name}.WebForms.Tests/bin/${build_config}/${project_name}.WebForms.Tests.dll",
   "${project_name}.WinForms.Tests/bin/${build_config}/${project_name}.WinForms.Tests.dll",
)

target default, (compile, test):
   pass

target zip, (compile, test, copy):
   zip("${build_folder}", "${project_name}.${build_version}.zip")
   rmdir(build_folder)

target deploy, (compile, test, copy):
   with FileList(build_folder):
    .Include("**/**")
    .ForEach def(file):
      file.CopyToDirectory("{project_name}.${build_version}")
   rmdir(build_folder)

target publish, (zip, publish_nuget, publish_github):
   pass

target compile:
   msbuild(file: "${project_name}.sln", configuration: build_config, version: "4")

   //Probably a reaaally crappy way to retrieve assembly version,
   //but I cannot use System.Reflection since Phantom is too old.
   content = File.ReadAllText("${assembly_file}")
   start_index = content.IndexOf("AssemblyVersion(") + 17
   content = content.Substring(start_index)
   end_index = content.IndexOf("\"")
   build_version = content.Substring(0, end_index)

target test:
   nunit(assemblies: test_assemblies, enableTeamCity: true, toolPath: "resources/phantom/lib/nunit/nunit-console.exe", teamCityArgs: "v4.0 x86 NUnit-2.5.5")
   exec("del TestResult.xml")

target copy:
   rmdir(build_folder)
   mkdir(build_folder)

   File.Copy("README.md", "${build_folder}/README.txt", true)
   File.Copy("Release-notes.md", "${build_folder}/Release-notes.txt", true)

   with FileList(""):
    .Include("**/bin/${build_config}/*.dll")
    .Include("**/bin/${build_config}/*.pdb")
    .Include("**/bin/${build_config}/*.xml")
    .Exclude("**/bin/${build_config}/*.Tests.*")
    .Exclude("**/bin/${build_config}/nunit.framework.*")
    .Exclude("**/bin/${build_config}/nsubstitute.*")
    .ForEach def(file):
      File.Copy(file.FullName, "${build_folder}/${file.Name}", true)

target publish_nuget:
   File.Copy("README.md", "Resources\\README.txt", true)
   File.Copy("Release-notes.md", "Resources\\Release-notes.txt", true)

   exec("Resources\\nuget" , "pack ${project_name}\\${project_name}.csproj -prop configuration=release")
   exec("Resources\\nuget" , "pack ${project_name}.web\\${project_name}.web.csproj -prop configuration=release")
   exec("Resources\\nuget" , "pack ${project_name}.mvc\\${project_name}.mvc.csproj -prop configuration=release")
   exec("Resources\\nuget" , "pack ${project_name}.wpf\\${project_name}.wpf.csproj -prop configuration=release")
   exec("Resources\\nuget" , "pack ${project_name}.webforms\\${project_name}.webforms.csproj -prop configuration=release")
   exec("Resources\\nuget" , "pack ${project_name}.winforms\\${project_name}.winforms.csproj -prop configuration=release")

   exec("Resources\\nuget push ${project_name}.${build_version}.nupkg")
   exec("Resources\\nuget push ${project_name}.web.${build_version}.nupkg")
   exec("Resources\\nuget push ${project_name}.mvc.${build_version}.nupkg")
   exec("Resources\\nuget push ${project_name}.wpf.${build_version}.nupkg")
   exec("Resources\\nuget push ${project_name}.webforms.${build_version}.nupkg")
   exec("Resources\\nuget push ${project_name}.winforms.${build_version}.nupkg")

   exec("del *.nupkg")
   exec("del Resources\\README.txt")
   exec("del Resources\\Release-notes.txt")

target publish_github:
   exec("git add .")
   exec('git commit . -m "Publishing ${project_name} ' + "${build_version}" + '"')
   exec("git tag ${build_version}")
   exec("git push origin master")
   exec("git push origin ${build_version}")

import System.IO

project_name  = "NExtra"
assembly_file = "SharedAssemblyInfo.cs"

build_folder  = "_tmpbuild_/"
build_version = ""
build_config  = env('config')

test_assemblies = (
   "${project_name}.Tests/bin/${build_config}/${project_name}.Tests.dll",
   "${project_name}.Web.Tests/bin/${build_config}/${project_name}.Web.Tests.dll",
   "${project_name}.Mvc.Tests/bin/${build_config}/${project_name}.Mvc.Tests.dll",
   "${project_name}.WPF.Tests/bin/${build_config}/${project_name}.WPF.Tests.dll",
   "${project_name}.WebForms.Tests/bin/${build_config}/${project_name}.WebForms.Tests.dll",
   "${project_name}.WinForms.Tests/bin/${build_config}/${project_name}.WinForms.Tests.dll",
)

target default, (compile, test):
   pass

target zip, (compile, test, copy):
   zip("${build_folder}", "${project_name}.${build_version}.zip")
   rmdir(build_folder)

target deploy, (compile, test, copy):
   with FileList(build_folder):
    .Include("**/**")
    .ForEach def(file):
      file.CopyToDirectory("{project_name}.${build_version}")
   rmdir(build_folder)

target publish, (publish_nuget, publish_github):
   pass

target compile:
   msbuild(file: "${project_name}.sln", configuration: build_config, version: "4")

   //Probably a reaaally crappy way to retrieve assembly version,
   //but I cannot use System.Reflection since Phantom is too old.
   content = File.ReadAllText("${assembly_file}")
   start_index = content.IndexOf("AssemblyVersion(") + 17
   content = content.Substring(start_index)
   end_index = content.IndexOf("\"")
   build_version = content.Substring(0, end_index)

target test:
   nunit(assemblies: test_assemblies, enableTeamCity: true, toolPath: "resources/phantom/lib/nunit/nunit-console.exe", teamCityArgs: "v4.0 x86 NUnit-2.5.5")
   exec("del TestResult.xml")

target copy:
   rmdir(build_folder)
   mkdir(build_folder)

   File.Copy("README.md", "${build_folder}/README.txt", true)
   File.Copy("Release-notes.md", "${build_folder}/Release-notes.txt", true)

   with FileList(""):
    .Include("**/bin/${build_config}/*.dll")
    .Include("**/bin/${build_config}/*.pdb")
    .Include("**/bin/${build_config}/*.xml")
    .Exclude("**/bin/${build_config}/*.Tests.*")
    .Exclude("**/bin/${build_config}/nunit.framework.*")
    .Exclude("**/bin/${build_config}/nsubstitute.*")
    .ForEach def(file):
      File.Copy(file.FullName, "${build_folder}/${file.Name}", true)

target publish_nuget:
   File.Copy("README.md", "Resources\\README.txt", true)
   File.Copy("Release-notes.md", "Resources\\Release-notes.txt", true)

   exec("Resources\\nuget" , "pack ${project_name}\\${project_name}.csproj -prop configuration=release")
   exec("Resources\\nuget" , "pack ${project_name}.web\\${project_name}.web.csproj -prop configuration=release")
   exec("Resources\\nuget" , "pack ${project_name}.mvc\\${project_name}.mvc.csproj -prop configuration=release")
   exec("Resources\\nuget" , "pack ${project_name}.wpf\\${project_name}.wpf.csproj -prop configuration=release")
   exec("Resources\\nuget" , "pack ${project_name}.webforms\\${project_name}.webforms.csproj -prop configuration=release")
   exec("Resources\\nuget" , "pack ${project_name}.winforms\\${project_name}.winforms.csproj -prop configuration=release")

   exec("Resources\\nuget push ${project_name}.${build_version}.nupkg")
   exec("Resources\\nuget push ${project_name}.web.${build_version}.nupkg")
   exec("Resources\\nuget push ${project_name}.mvc.${build_version}.nupkg")
   exec("Resources\\nuget push ${project_name}.wpf.${build_version}.nupkg")
   exec("Resources\\nuget push ${project_name}.webforms.${build_version}.nupkg")
   exec("Resources\\nuget push ${project_name}.winforms.${build_version}.nupkg")

   exec("del *.nupkg")
   exec("del Resources\\README.txt")
   exec("del Resources\\Release-notes.txt")

target publish_github:
   exec("git add .")
   exec('git commit . -m "Publishing ${project_name} ' + "${build_version}" + '"')
   exec("git tag ${build_version}")
   exec("git push origin master")
   exec("git push origin ${build_version}")


Fixed loop for array literals

Fixed loop for array literals

namespace BooJs.Compiler.Steps

import System
import Boo.Lang.Environments
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps(AbstractTransformerCompilerStep)
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler(CompilerContext)
import Boo.Lang.PatternMatching

import BooJs.Compiler.TypeSystem.RuntimeMethodCache as RuntimeMethodCache

class NormalizeLoops(AbstractTransformerCompilerStep):
"""
    Normalize loops

    The current implementation is very naive, it won't inspect the type system to
    choose a proper loop strategy. This should be done in the future using a compiler
    step.

    - If it contains a yield statement it's converted to an equivalent while loop.
    - If it has an Or or Then block it's converted to a while loop
    - If it is an array we convert it to a for in range
    - When the iterator is the range method it's left to be optimized when converting
      to the Mozilla AST
    - If it contains a return convert to a while loop
    - If iterator is not an array iterate it with Boo.each()

    for i in arr:
    ---
    for __idx in range(len(arr)):
        i = arr[__idx]

    for x, y in arr:
    ---
    for __idx in range(len(arr)):
        x, y = arr[__idx]

    for i in iter:
    ---
    Boo.each(iter) do (i):
        pass

    for i in ducky():
    ---
    __for1 = Boo.generator(ducky())
    try:
        while @(i = __for.next(), true):
            pass
    except e if e is Boo.STOP:
        pass
    ensure:
        __for1.close()

    Boo's for statement does not allow to specify a receiving variable for the key like it's
    done in CoffeeScript (for v, k in hash), however it allows to defines multiple variables
    for unpacking. So the solution is to disable the support for unpacking and use it instead
    to obtain the key.

        for v, k in obj: ...
        ---
        Boo.each(obj, {v,k| ...})
"""

    class NodeFinder(DepthFirstVisitor):
        [property(Accepted)]
        _accepted as (NodeType)

        [property(Skipped)]
        _skipped as (NodeType)

        _found as bool

        def Run(node as Node) as bool:
            _found = false
            Visit(node)
            return _found

        override def Visit(node as Node):
            if node is null or _found:
                return
            elif node.NodeType in Accepted:
                _found = true
                return
            elif node.NodeType in Skipped:
                return
            else:
                super(node)

    _yieldFinder = NodeFinder(
        Accepted: (NodeType.YieldStatement,),
        Skipped: (NodeType.Method, NodeType.BlockExpression)
    )

    _returnFinder = NodeFinder(
        Accepted: (NodeType.ReturnStatement,),
        Skipped: (NodeType.Method, NodeType.BlockExpression)
    )

    [getter(MethodCache)]
    _methodCache as RuntimeMethodCache

    [property(CurrentMethod)]
    _method as Method

    override def OnMethod(node as Method):
        prev = CurrentMethod
        CurrentMethod = node
        super(node)
        CurrentMethod = prev

    override def OnConstructor(node as Constructor):
        prev = CurrentMethod
        CurrentMethod = node
        super(node)
        CurrentMethod = prev

    override def Initialize(ctxt as CompilerContext):
        super(ctxt)
        _methodCache = my(RuntimeMethodCache)

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

    protected def HasYield(node as Node):
        return _yieldFinder.Run(node)

    protected def HasReturn(node as Node):
        return _returnFinder.Run(node)

    protected def IsLiteralRange(node as Node):
        # We only support optimizations for simple ranges with positive integers
        if mie = node as MethodInvocationExpression and entity = mie.Target.Entity:
            if entity is MethodCache.Range1 and ile = mie.Arguments[0] as IntegerLiteralExpression:
                return ile.Value >= 0
            if entity is MethodCache.Range2 and ile1 = mie.Arguments[0] as IntegerLiteralExpression and \
               ile2 = mie.Arguments[1] as IntegerLiteralExpression:
                return ile1.Value >= 0 and ile1.Value <= ile2.Value

        return false

    protected def IsArray(node as Expression):
        # TODO: Detect Globals.Array here too?
        type = GetExpressionType(node)
        return type and type.IsArray

    protected def ForToWhile(node as ForStatement) as Statement:
        mie = CodeBuilder.CreateMethodInvocation([| Boo.generator |], MethodCache.Generator, node.Iterator)
        tmpref = TempLocalInMethod(CurrentMethod, mie.ExpressionType, Context.GetUniqueName('for'))

        eval = CodeBuilder.CreateEvalInvocation(node.LexicalInfo)
        if len(node.Declarations) > 1:
            tmpupk = TempLocalInMethod(CurrentMethod, node.Iterator.ExpressionType, Context.GetUniqueName('upk'))
            eval.Arguments.Add([| $tmpupk = $(tmpref).next() |])
            for i as int, decl as Declaration in enumerate(node.Declarations):
                eval.Arguments.Add([| $(ReferenceExpression(decl.Name)) = $tmpupk[$i] |])
        else:
            eval.Arguments.Add([| $(ReferenceExpression(node.Declarations[0].Name)) = $(tmpref).next() |])

        # Make sure we always enter the loop
        eval.Arguments.Add(BoolLiteralExpression(Value: true))

        whilest = WhileStatement(node.LexicalInfo)
        whilest.Condition = [| $tmpref and $eval |]
        whilest.Block = node.Block

        result = [|
            $tmpref = $mie
            try:
                $whilest
            except __e if __e is Boo.STOP:
                pass
            ensure:
                $tmpref.close()
        |]

        if node.OrBlock or node.ThenBlock:
            flagref = TempLocalInMethod(CurrentMethod, TypeSystemServices.IntType, Context.GetUniqueName('flag'))
            result.Insert(1, [| $flagref = Boo.LOOP_OR | Boo.LOOP_THEN |])

            if node.OrBlock:
                whilest.Block.Insert(0, [| $flagref &= ~Boo.LOOP_OR |])
                st = [|
                    if $flagref & Boo.LOOP_OR:
                        $(node.OrBlock)
                |]
                result.Add(st)

            if node.ThenBlock:
                FlagBreaks(flagref, whilest.Block)
                st = [|
                    if $flagref & Boo.LOOP_THEN:
                        $(node.ThenBlock)
                |]
                result.Add(st)

        return result

    protected def ForToEach(node as ForStatement) as Statement:
        # Handle nested loops
        Visit node.Block

        ProcessContinueBreakForEach(node.Block)

        # TODO: Unlike Boo, the loop declarations are bound to the loop scope
        callback = BlockExpression(Body: node.Block)
        for decl in node.Declarations:
            param = ParameterDeclaration(decl.Name, decl.Type, LexicalInfo: decl.LexicalInfo)
            callback.Parameters.Add(param)

        # Use the runtime helper to iterate
        each = CodeBuilder.CreateMethodReference(MethodCache.Each)
        mie = [| $each($(node.Iterator), $callback) |]
        return ExpressionStatement(mie)

    protected def ForToIndex(node as ForStatement) as Statement:
    """ Converts a for-in loop iterating over the values of an Array to a loop
        iterating over the indexes in that Array.

            for v in items:
            ---
            for i in range(items.length):
                v = items[i]

    """

        Visit node.Block

        result = Block()
        result.Add(node)

        # If the target iterator is already a reference there is no need to alias it to a temp
        iter as ReferenceExpression
        if node.Iterator.NodeType == NodeType.ReferenceExpression:
            iter = node.Iterator
        else:
            ent as ITypedEntity
            if node.Iterator.NodeType == NodeType.ArrayLiteralExpression:
                ent = (node.Iterator as ArrayLiteralExpression).Type.Entity
            else:
                ent = node.Iterator.Entity

            iter = TempLocalInMethod(CurrentMethod, ent.Type, Context.GetUniqueName('for'))
            result.Insert(0, [| $iter = $(node.Iterator) |])

        # Create a temporary variable to hold the iteration index
        tmpidx = TempLocalInMethod(CurrentMethod, TypeSystemServices.IntType, Context.GetUniqueName('idx'))

        # Handle declaration unpacking
        decls = node.Declarations
        if len(decls) > 1:
            eval = CodeBuilder.CreateEvalInvocation(node.LexicalInfo)
            tmpupk = TempLocalInMethod(CurrentMethod, node.Iterator.ExpressionType, Context.GetUniqueName('upk'))
            eval.Arguments.Add([| $tmpupk = $iter[$tmpidx] |])
            for i as int, decl as Declaration in enumerate(decls):
                eval.Arguments.Add([| $(ReferenceExpression(decl.Name)) = $tmpupk[$i] |])
            node.Block.Insert(0, eval)
        else:
            node.Block.Insert(0, [| $(ReferenceExpression(decls[0].Name)) = $iter[$tmpidx] |])

        # Replace any declarations by the temporal variable holding the index
        decls.Clear()
        decls.Add(Declaration(Name: tmpidx.Name))

        # Override the iterator so we iterate over the indexes
        node.Iterator = CodeBuilder.CreateMethodInvocation(
            [| BooJs.Lang.Builtins.range |],
            MethodCache.Range1,
            [| $iter.length |])

        return result

    override def OnForStatement(node as ForStatement):
        # Make sure we only normalize once
        return if node.ContainsAnnotation('for-normalized')
        node['for-normalized'] = true

        # If it contains a yield statement or has and Or or Then block
        if HasYield(node) or node.OrBlock or node.ThenBlock:
            ReplaceCurrentNode ForToWhile(node)
        # Check if it can be optimized in the generated output
        elif IsLiteralRange(node.Iterator):
            # Nothing to do here, we will process it before generating the Javascript
            TempLocalInMethod(CurrentMethod, TypeSystemServices.IntType, node.Declarations[0].Name)
            Visit node.Block
        # If it's an array create an optimizable version of the loop
        elif IsArray(node.Iterator):
            ReplaceCurrentNode ForToIndex(node)
        # If it has a return statement use a while
        elif HasReturn(node):
            ReplaceCurrentNode ForToWhile(node)
        # Any other case uses the Boo.each runtime method to handle the iteration
        else:
            ReplaceCurrentNode ForToEach(node)

    override def LeaveWhileStatement(node as WhileStatement):
        if node.OrBlock or node.ThenBlock:
            ReplaceCurrentNode ProcessWhile(node)

    protected def ProcessWhile(node as WhileStatement) as Statement:
        tmpref = TempLocalInMethod(CurrentMethod, TypeSystemServices.IntType, Context.GetUniqueName('flag'))
        result = [|
            $tmpref = Boo.LOOP_OR | Boo.LOOP_THEN
            while $(node.Condition):
                $tmpref &= ~Boo.LOOP_OR
                $(node.Block)
        |]

        if node.OrBlock and not node.OrBlock.IsEmpty:
            st = [|
                if $tmpref & Boo.LOOP_OR:
                    $(node.OrBlock)
            |]
            result.Add(st)

        if node.ThenBlock and not node.ThenBlock.IsEmpty:
            FlagBreaks(tmpref, node.Block)
            st = [|
                if $tmpref & Boo.LOOP_THEN:
                    $(node.ThenBlock)
            |]
            result.Add(st)

        return result

    protected def TempLocalInMethod(method as Method, type as IType, name as string):
        def exists(name):
            found = false
            for local in method.Locals:
                if local.Name == name:
                    found = true
                    break
            return found

        # Find a name that doesn't exists
        cnt = 1
        while exists(name):
            name = name + cnt
            cnt++

        # Reference the local in the method
        CodeBuilder.DeclareLocal(method, name, type)
        return ReferenceExpression(Name:name)

    protected def ProcessContinueBreakForEach(node as Block) as void:
    """ Replaces the continue keyword with a return and the break one with a return of Boo.STOP
    """
        for st in node.Statements:
            match st:
                case ContinueStatement():
                    node.Replace(st, ReturnStatement(st.LexicalInfo))
                case BreakStatement():
                    boo = CodeBuilder.CreateTypedReference('Boo', TypeSystemServices.BuiltinsType)
                    node.Replace(st, ReturnStatement(st.LexicalInfo, Expression: [| $boo.STOP |]))
                case bst=Block():
                    ProcessContinueBreakForEach(bst)
                case ist=IfStatement():
                    ProcessContinueBreakForEach(ist.TrueBlock)
                    ProcessContinueBreakForEach(ist.FalseBlock) if ist.FalseBlock
                case tst=TryStatement():
                    ProcessContinueBreakForEach(tst.ProtectedBlock)
                    for hdlr in tst.ExceptionHandlers:
                        ProcessContinueBreakForEach(hdlr.Block)
                    ProcessContinueBreakForEach(tst.EnsureBlock) if tst.EnsureBlock
                otherwise:
                    continue

    protected def FlagBreaks(tmpref as ReferenceExpression, block as Block):
    """ Prepends all break statements with an unflagging operation for the Then block
    """
        for st in block.Statements:
            match st:
                case ist=IfStatement():
                    FlagBreaks(tmpref, ist.TrueBlock)
                    FlagBreaks(tmpref, ist.FalseBlock) if ist.FalseBlock
                case tst=TryStatement():
                    FlagBreaks(tmpref, tst.ProtectedBlock)
                    FlagBreaks(tmpref, tst.EnsureBlock) if tst.EnsureBlock
                    for hdlr in tst.ExceptionHandlers:
                        FlagBreaks(tmpref, hdlr.Block)
                case BreakStatement():
                    idx = block.Statements.IndexOf(st)
                    block.Insert(idx, [| $tmpref &= ~Boo.LOOP_THEN |])
                    return
                otherwise:
                    continue

namespace BooJs.Compiler.Steps

import System
import Boo.Lang.Environments
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps(AbstractTransformerCompilerStep)
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler(CompilerContext)
import Boo.Lang.PatternMatching

import BooJs.Compiler.TypeSystem.RuntimeMethodCache as RuntimeMethodCache

class NormalizeLoops(AbstractTransformerCompilerStep):
"""
    Normalize loops

    The current implementation is very naive, it won't inspect the type system to
    choose a proper loop strategy. This should be done in the future using a compiler
    step.

    - If it contains a yield statement it's converted to an equivalent while loop.
    - If it has an Or or Then block it's converted to a while loop
    - If it is an array we convert it to a for in range
    - When the iterator is the range method it's left to be optimized when converting
      to the Mozilla AST
    - If it contains a return convert to a while loop
    - If iterator is not an array iterate it with Boo.each()

    for i in arr:
    ---
    for __idx in range(len(arr)):
        i = arr[__idx]

    for x, y in arr:
    ---
    for __idx in range(len(arr)):
        x, y = arr[__idx]

    for i in iter:
    ---
    Boo.each(iter) do (i):
        pass

    for i in ducky():
    ---
    __for1 = Boo.generator(ducky())
    try:
        while @(i = __for.next(), true):
            pass
    except e if e is Boo.STOP:
        pass
    ensure:
        __for1.close()

    Boo's for statement does not allow to specify a receiving variable for the key like it's
    done in CoffeeScript (for v, k in hash), however it allows to defines multiple variables
    for unpacking. So the solution is to disable the support for unpacking and use it instead
    to obtain the key.

        for v, k in obj: ...
        ---
        Boo.each(obj, {v,k| ...})
"""

    class NodeFinder(DepthFirstVisitor):
        [property(Accepted)]
        _accepted as (NodeType)

        [property(Skipped)]
        _skipped as (NodeType)

        _found as bool

        def Run(node as Node) as bool:
            _found = false
            Visit(node)
            return _found

        override def Visit(node as Node):
            if node is null or _found:
                return
            elif node.NodeType in Accepted:
                _found = true
                return
            elif node.NodeType in Skipped:
                return
            else:
                super(node)

    _yieldFinder = NodeFinder(
        Accepted: (NodeType.YieldStatement,),
        Skipped: (NodeType.Method, NodeType.BlockExpression)
    )

    _returnFinder = NodeFinder(
        Accepted: (NodeType.ReturnStatement,),
        Skipped: (NodeType.Method, NodeType.BlockExpression)
    )

    [getter(MethodCache)]
    _methodCache as RuntimeMethodCache

    [property(CurrentMethod)]
    _method as Method

    override def OnMethod(node as Method):
        prev = CurrentMethod
        CurrentMethod = node
        super(node)
        CurrentMethod = prev

    override def OnConstructor(node as Constructor):
        prev = CurrentMethod
        CurrentMethod = node
        super(node)
        CurrentMethod = prev

    override def Initialize(ctxt as CompilerContext):
        super(ctxt)
        _methodCache = my(RuntimeMethodCache)

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

    protected def HasYield(node as Node):
        return _yieldFinder.Run(node)

    protected def HasReturn(node as Node):
        return _returnFinder.Run(node)

    protected def IsLiteralRange(node as Node):
        # We only support optimizations for simple ranges with positive integers
        if mie = node as MethodInvocationExpression and entity = mie.Target.Entity:
            if entity is MethodCache.Range1 and ile = mie.Arguments[0] as IntegerLiteralExpression:
                return ile.Value >= 0
            if entity is MethodCache.Range2 and ile1 = mie.Arguments[0] as IntegerLiteralExpression and \
               ile2 = mie.Arguments[1] as IntegerLiteralExpression:
                return ile1.Value >= 0 and ile1.Value <= ile2.Value

        return false

    protected def IsArray(node as Expression):
        # TODO: Detect Globals.Array here too?
        type = GetExpressionType(node)
        return type and type.IsArray

    protected def ForToWhile(node as ForStatement) as Statement:
        mie = CodeBuilder.CreateMethodInvocation([| Boo.generator |], MethodCache.Generator, node.Iterator)
        tmpref = TempLocalInMethod(CurrentMethod, mie.ExpressionType, Context.GetUniqueName('for'))

        eval = CodeBuilder.CreateEvalInvocation(node.LexicalInfo)
        if len(node.Declarations) > 1:
            tmpupk = TempLocalInMethod(CurrentMethod, node.Iterator.ExpressionType, Context.GetUniqueName('upk'))
            eval.Arguments.Add([| $tmpupk = $(tmpref).next() |])
            for i as int, decl as Declaration in enumerate(node.Declarations):
                eval.Arguments.Add([| $(ReferenceExpression(decl.Name)) = $tmpupk[$i] |])
        else:
            eval.Arguments.Add([| $(ReferenceExpression(node.Declarations[0].Name)) = $(tmpref).next() |])

        # Make sure we always enter the loop
        eval.Arguments.Add(BoolLiteralExpression(Value: true))

        whilest = WhileStatement(node.LexicalInfo)
        whilest.Condition = [| $tmpref and $eval |]
        whilest.Block = node.Block

        result = [|
            $tmpref = $mie
            try:
                $whilest
            except __e if __e is Boo.STOP:
                pass
            ensure:
                $tmpref.close()
        |]

        if node.OrBlock or node.ThenBlock:
            flagref = TempLocalInMethod(CurrentMethod, TypeSystemServices.IntType, Context.GetUniqueName('flag'))
            result.Insert(1, [| $flagref = Boo.LOOP_OR | Boo.LOOP_THEN |])

            if node.OrBlock:
                whilest.Block.Insert(0, [| $flagref &= ~Boo.LOOP_OR |])
                st = [|
                    if $flagref & Boo.LOOP_OR:
                        $(node.OrBlock)
                |]
                result.Add(st)

            if node.ThenBlock:
                FlagBreaks(flagref, whilest.Block)
                st = [|
                    if $flagref & Boo.LOOP_THEN:
                        $(node.ThenBlock)
                |]
                result.Add(st)

        return result

    protected def ForToEach(node as ForStatement) as Statement:
        # Handle nested loops
        Visit node.Block

        ProcessContinueBreakForEach(node.Block)

        # TODO: Unlike Boo, the loop declarations are bound to the loop scope
        callback = BlockExpression(Body: node.Block)
        for decl in node.Declarations:
            param = ParameterDeclaration(decl.Name, decl.Type, LexicalInfo: decl.LexicalInfo)
            callback.Parameters.Add(param)

        # Use the runtime helper to iterate
        each = CodeBuilder.CreateMethodReference(MethodCache.Each)
        mie = [| $each($(node.Iterator), $callback) |]
        return ExpressionStatement(mie)

    protected def ForToIndex(node as ForStatement) as Statement:
    """ Converts a for-in loop iterating over the values of an Array to a loop
        iterating over the indexes in that Array.

            for v in items:
            ---
            for i in range(items.length):
                v = items[i]

    """

        Visit node.Block

        result = Block()
        result.Add(node)

        # If the target iterator is already a reference there is no need to alias it to a temp
        iter as ReferenceExpression
        if node.Iterator.NodeType == NodeType.ReferenceExpression:
            iter = node.Iterator
        else:
            iter = TempLocalInMethod(
                CurrentMethod, (node.Iterator.Entity as ITypedEntity).Type, Context.GetUniqueName('for'))
            result.Insert(0, [| $iter = $(node.Iterator) |])

        # Create a temporary variable to hold the iteration index
        tmpidx = TempLocalInMethod(CurrentMethod, TypeSystemServices.IntType, Context.GetUniqueName('idx'))

        # Handle declaration unpacking
        decls = node.Declarations
        if len(decls) > 1:
            eval = CodeBuilder.CreateEvalInvocation(node.LexicalInfo)
            tmpupk = TempLocalInMethod(CurrentMethod, node.Iterator.ExpressionType, Context.GetUniqueName('upk'))
            eval.Arguments.Add([| $tmpupk = $iter[$tmpidx] |])
            for i as int, decl as Declaration in enumerate(decls):
                eval.Arguments.Add([| $(ReferenceExpression(decl.Name)) = $tmpupk[$i] |])
            node.Block.Insert(0, eval)
        else:
            node.Block.Insert(0, [| $(ReferenceExpression(decls[0].Name)) = $iter[$tmpidx] |])

        # Replace any declarations by the temporal variable holding the index
        decls.Clear()
        decls.Add(Declaration(Name: tmpidx.Name))

        # Override the iterator so we iterate over the indexes
        node.Iterator = CodeBuilder.CreateMethodInvocation(
            [| BooJs.Lang.Builtins.range |],
            MethodCache.Range1,
            [| $iter.length |])

        return result

    override def OnForStatement(node as ForStatement):
        # Make sure we only normalize once
        return if node.ContainsAnnotation('for-normalized')
        node['for-normalized'] = true

        # If it contains a yield statement or has and Or or Then block
        if HasYield(node) or node.OrBlock or node.ThenBlock:
            ReplaceCurrentNode ForToWhile(node)
        # Check if it can be optimized in the generated output
        elif IsLiteralRange(node.Iterator):
            # Nothing to do here, we will process it before generating the Javascript
            TempLocalInMethod(CurrentMethod, TypeSystemServices.IntType, node.Declarations[0].Name)
            Visit node.Block
        # If it's an array create an optimizable version of the loop
        elif IsArray(node.Iterator):
            ReplaceCurrentNode ForToIndex(node)
        # If it has a return statement use a while
        elif HasReturn(node):
            ReplaceCurrentNode ForToWhile(node)
        # Any other case uses the Boo.each runtime method to handle the iteration
        else:
            ReplaceCurrentNode ForToEach(node)

    override def LeaveWhileStatement(node as WhileStatement):
        if node.OrBlock or node.ThenBlock:
            ReplaceCurrentNode ProcessWhile(node)

    protected def ProcessWhile(node as WhileStatement) as Statement:
        tmpref = TempLocalInMethod(CurrentMethod, TypeSystemServices.IntType, Context.GetUniqueName('flag'))
        result = [|
            $tmpref = Boo.LOOP_OR | Boo.LOOP_THEN
            while $(node.Condition):
                $tmpref &= ~Boo.LOOP_OR
                $(node.Block)
        |]

        if node.OrBlock and not node.OrBlock.IsEmpty:
            st = [|
                if $tmpref & Boo.LOOP_OR:
                    $(node.OrBlock)
            |]
            result.Add(st)

        if node.ThenBlock and not node.ThenBlock.IsEmpty:
            FlagBreaks(tmpref, node.Block)
            st = [|
                if $tmpref & Boo.LOOP_THEN:
                    $(node.ThenBlock)
            |]
            result.Add(st)

        return result

    protected def TempLocalInMethod(method as Method, type as IType, name as string):
        def exists(name):
            found = false
            for local in method.Locals:
                if local.Name == name:
                    found = true
                    break
            return found

        # Find a name that doesn't exists
        cnt = 1
        while exists(name):
            name = name + cnt
            cnt++

        # Reference the local in the method
        CodeBuilder.DeclareLocal(method, name, type)
        return ReferenceExpression(Name:name)

    protected def ProcessContinueBreakForEach(node as Block) as void:
    """ Replaces the continue keyword with a return and the break one with a return of Boo.STOP
    """
        for st in node.Statements:
            match st:
                case ContinueStatement():
                    node.Replace(st, ReturnStatement(st.LexicalInfo))
                case BreakStatement():
                    boo = CodeBuilder.CreateTypedReference('Boo', TypeSystemServices.BuiltinsType)
                    node.Replace(st, ReturnStatement(st.LexicalInfo, Expression: [| $boo.STOP |]))
                case bst=Block():
                    ProcessContinueBreakForEach(bst)
                case ist=IfStatement():
                    ProcessContinueBreakForEach(ist.TrueBlock)
                    ProcessContinueBreakForEach(ist.FalseBlock) if ist.FalseBlock
                case tst=TryStatement():
                    ProcessContinueBreakForEach(tst.ProtectedBlock)
                    for hdlr in tst.ExceptionHandlers:
                        ProcessContinueBreakForEach(hdlr.Block)
                    ProcessContinueBreakForEach(tst.EnsureBlock) if tst.EnsureBlock
                otherwise:
                    continue

    protected def FlagBreaks(tmpref as ReferenceExpression, block as Block):
    """ Prepends all break statements with an unflagging operation for the Then block
    """
        for st in block.Statements:
            match st:
                case ist=IfStatement():
                    FlagBreaks(tmpref, ist.TrueBlock)
                    FlagBreaks(tmpref, ist.FalseBlock) if ist.FalseBlock
                case tst=TryStatement():
                    FlagBreaks(tmpref, tst.ProtectedBlock)
                    FlagBreaks(tmpref, tst.EnsureBlock) if tst.EnsureBlock
                    for hdlr in tst.ExceptionHandlers:
                        FlagBreaks(tmpref, hdlr.Block)
                case BreakStatement():
                    idx = block.Statements.IndexOf(st)
                    block.Insert(idx, [| $tmpref &= ~Boo.LOOP_THEN |])
                    return
                otherwise:
                    continue


pretty printing for StringFormattingExpression

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

#region license
// boo - an extensible programming language for the CLI
// Copyright (C) 2004 Rodrigo B. de Oliveira
//
// This program 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.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// As a special exception, if you link this library with other files to
// produce an executable, this library does not by itself cause the
// resulting executable to be covered by the GNU General Public License.
// This exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
//
// Contact Information
//
// mailto:rbo@acm.org
#endregion

namespace Boo.Examples.Web

import System
import System.IO
import System.Web
import System.Web.UI
import System.Web.UI.WebControls
import System.Web.UI.HtmlControls
import Boo.Antlr
import Boo.Lang.Ast
import Boo.Lang.Ast.Visitors

class PrettyPrinter(BooPrinterVisitor):

	Server = HttpContext.Current.Server

	def constructor(writer as TextWriter):
		super(writer)

	def Write(text as string):
		Server.HtmlEncode(text, _writer)

	def WriteLine():
		_writer.Write("
")
		super()

	def WriteKeyword(text as string):
		_writer.Write("${text}")

	def WriteOperator(text as string):
		_writer.Write("${Server.HtmlEncode(text)}")

	override def OnStringFormattingExpression(node as StringFormattingExpression):
		_writer.Write("")
		super(node)
		_writer.Write("")

	def WriteStringLiteral(text as string):
		_writer.Write("")
		buffer = StringWriter()
		BooPrinterVisitor.WriteStringLiteral(text, buffer)
		Server.HtmlEncode(buffer.ToString(), _writer)
		_writer.Write("")

	def OnIntegerLiteralExpression(node as IntegerLiteralExpression):
		_writer.Write("${node.Value}")

class PrettyPrinterPage(Page):

	_src as TextBox
	_pretty as HtmlContainerControl

	def Page_Load(sender, args as EventArgs):
		PrettyPrint() if Page.IsPostBack

	def PrettyPrint():
		printer = PrettyPrinter(StringWriter(), IndentText: "  ")
		printer.Print(Parse())
		_pretty.InnerHtml = printer.Writer.ToString()

	def Parse():
		return BooParser.ParseString("<string>", _src.Text)

#region license
// boo - an extensible programming language for the CLI
// Copyright (C) 2004 Rodrigo B. de Oliveira
//
// This program 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.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// As a special exception, if you link this library with other files to
// produce an executable, this library does not by itself cause the
// resulting executable to be covered by the GNU General Public License.
// This exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
//
// Contact Information
//
// mailto:rbo@acm.org
#endregion

namespace Boo.Examples.Web

import System
import System.IO
import System.Web
import System.Web.UI
import System.Web.UI.WebControls
import System.Web.UI.HtmlControls
import Boo.Antlr
import Boo.Lang.Ast
import Boo.Lang.Ast.Visitors

class PrettyPrinter(BooPrinterVisitor):

	Server = HttpContext.Current.Server

	def constructor(writer as TextWriter):
		super(writer)

	def Write(text as string):
		Server.HtmlEncode(text, _writer)

	def WriteLine():
		_writer.Write("
")
		super()

	def WriteKeyword(text as string):
		_writer.Write("${text}")

	def WriteOperator(text as string):
		_writer.Write("${Server.HtmlEncode(text)}")

	def WriteStringLiteral(text as string):
		_writer.Write("")
		buffer = StringWriter()
		BooPrinterVisitor.WriteStringLiteral(text, buffer)
		Server.HtmlEncode(buffer.ToString(), _writer)
		_writer.Write("")

	def OnIntegerLiteralExpression(node as IntegerLiteralExpression):
		_writer.Write("${node.Value}")

class PrettyPrinterPage(Page):

	_src as TextBox
	_pretty as HtmlContainerControl

	def Page_Load(sender, args as EventArgs):
		PrettyPrint() if Page.IsPostBack

	def PrettyPrint():
		printer = PrettyPrinter(StringWriter(), IndentText: "  ")
		printer.Print(Parse())
		_pretty.InnerHtml = printer.Writer.ToString()

	def Parse():
		return BooParser.ParseString("<string>", _src.Text)


Support defines in command line

Support defines in command line

namespace booi

from System import Environment
from System.IO import Path
from Boo.Lang.Useful.CommandLine import *

class CommandLine(AbstractCommandLine):

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

    [getter(Files)]
    _files = List[of string]()

    [getter(Defines)]
    _defines = {}

    IsValid:
        get: return true

    [Option("Turns on duck typing by default", LongForm: "ducky")]
    public Ducky = false

    [Option("Generate debugging information (default: +)", LongForm: "debug")]
    public Debug = true

    [Option("Turns on strict mode", LongForm: "strict")]
    public Strict = false

    [Option("Enables white-space-agnostic build", LongForm: "wsa")]
    public Wsa = false

    [Option("Report warnings (default: -)", ShortForm: "w", LongForm: "warnings")]
    public Warnings = false

    [Option("Generate verbose information (default: -)", ShortForm: "v", LongForm: "verbose")]
    public Verbose = false

    [Option("Defines a {symbol}s with optional values (=val)", ShortForm: "d", LongForm: "define")]
    def AddDefine(define as string):
        if not define:
            raise CommandLineException("No value given for the define")

        parts = define.Split(char('='), 2)
        _defines[ parts[0] ] = (null if len(parts) == 1 else parts[1])

    [Option("Adds the comma-separated DIRS to the assembly search path", LongForm: "lib")]
    public LibPaths = ''

    [Option("References {assembly}", ShortForm: 'r', LongForm: "reference", MaxOccurs: int.MaxValue)]
    def AddReference(reference as string):
        if not reference:
            raise CommandLineException("No reference given (ie: -r:my.project.reference)")
        _references.AddUnique(TranslatePath(reference))

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

    [Option("Display program version", LongForm: "version")]
    public DoVersion = false

    [Argument]
    def AddFile([required] file as string):
        _files.Add(TranslatePath(file))

    def constructor(argv):
        Parse(argv)

    IsCygwin:
        get: return Environment.GetEnvironmentVariable("TERM") == "cygwin"

    CygwinRoot:
        get:
            home = Environment.GetEnvironmentVariable("HOME")
            assert home is not null
            return home[:home.IndexOf("\\home")]

    protected def TranslatePath(path as string):
        if path.StartsWith('"') or path.StartsWith("'"):
            path = path[1:-1]

        if not IsCygwin or not path.StartsWith('/'):
            return path

        if path.StartsWith('/cygdrive/'):
            path = path[len('/cygdrive/'):]
            drive = path[0]
            return drive + ':' + path[1:]

        return Path.Combine(CygwinRoot, path[1:])

namespace booi

from System import Environment
from System.IO import Path
from Boo.Lang.Useful.CommandLine import *

class CommandLine(AbstractCommandLine):

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

    [getter(Files)]
    _files = List[of string]()

    [getter(Defines)]
    _defines = List[of string]()

    IsValid:
        get: return true

    [Option("Turns on duck typing by default", LongForm: "ducky")]
    public Ducky = false

    [Option("Generate debugging information (default: +)", LongForm: "debug")]
    public Debug = true

    [Option("Turns on strict mode", LongForm: "strict")]
    public Strict = false

    [Option("Enables white-space-agnostic build", LongForm: "wsa")]
    public Wsa = false

    [Option("Report warnings (default: -)", ShortForm: "w", LongForm: "warnings")]
    public Warnings = false

    [Option("Generate verbose information (default: -)", ShortForm: "v", LongForm: "verbose")]
    public Verbose = false

    [Option("Defines a {symbol}s with optional values (=val)", ShortForm: "d", LongForm: "define")]
    def AddDefine(define as string):
        if not define:
            raise CommandLineException("No value given for the define")
        _defines.Add(define)

    [Option("Adds the comma-separated DIRS to the assembly search path", LongForm: "lib")]
    public LibPaths = ''

    [Option("References {assembly}", ShortForm: 'r', LongForm: "reference", MaxOccurs: int.MaxValue)]
    def AddReference(reference as string):
        if not reference:
            raise CommandLineException("No reference given (ie: -r:my.project.reference)")
        _references.AddUnique(TranslatePath(reference))

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

    [Option("Display program version", LongForm: "version")]
    public DoVersion = false

    [Argument]
    def AddFile([required] file as string):
        _files.Add(TranslatePath(file))

    def constructor(argv):
        Parse(argv)

    IsCygwin:
        get: return Environment.GetEnvironmentVariable("TERM") == "cygwin"

    CygwinRoot:
        get:
            home = Environment.GetEnvironmentVariable("HOME")
            assert home is not null
            return home[:home.IndexOf("\\home")]

    protected def TranslatePath(path as string):
        if path.StartsWith('"') or path.StartsWith("'"):
            path = path[1:-1]

        if not IsCygwin or not path.StartsWith('/'):
            return path

        if path.StartsWith('/cygdrive/'):
            path = path[len('/cygdrive/'):]
            drive = path[0]
            return drive + ':' + path[1:]

        return Path.Combine(CygwinRoot, path[1:])


minor cleanup

minor cleanup

#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.Lang.Extensions

import System
import Boo.Lang.Compiler.Ast

class VolatileAttribute(Boo.Lang.Compiler.AbstractAstAttribute):

	override def Apply(node as Node):
		f = node as Field
		if f is null:
			InvalidNodeForAttribute('Field')
			return
		f.IsVolatile = true

#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.Lang.Extensions

import System
import Boo.Lang.Compiler.Ast

public class VolatileAttribute (Boo.Lang.Compiler.AbstractAstAttribute):

	public override def Apply(node as Node):
		f = node as Field
		if f is null:
			InvalidNodeForAttribute('Field')
			return
		f.IsVolatile = true


don't try to generate debugging information for eval code

namespace UnityScript.Scripting

import System
import UnityScript
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO

class CompilationErrorsException(Exception):

	[getter(Errors)]
	_errors as CompilerErrorCollection

	def constructor(errors as CompilerErrorCollection):
		super(errors.ToString(true))
		_errors = errors

interface IEvaluationDomainProvider:
"""
Every script in UnityScript defines a new EvaluationDomain.
"""
	def GetImports() as (string)
	def GetEvaluationDomain() as EvaluationDomain

class SimpleEvaluationDomainProvider(IEvaluationDomainProvider):
"""
SimpleEvaluationDomainProvider is used whenever there's an eval invocation
inside a static method.
"""
	private _domain = EvaluationDomain()
	private _imports as (string)

	def GetImports():
		return _imports

	def GetEvaluationDomain() as EvaluationDomain:
		return _domain

class EvaluationDomain:
"""
Groups together a set of related EvaluationScripts instances.
"""
	_cache = {}

	[lock]
	def GetCachedScript(key as EvaluationScriptCacheKey) as System.Type:
		return _cache[key]

	[lock]
	def CacheScript(key as EvaluationScriptCacheKey, type as System.Type):
		_cache[key] = type

class EvaluationScriptCacheKey:

	_contextType as System.Type
	_code as string

	def constructor(contextType as Type, code as string):
		_contextType = contextType
		_code = code

	override def Equals(o):
		other = o as EvaluationScriptCacheKey
		if other is null: return false
		return other._contextType is _contextType and other._code == _code

	override def GetHashCode():
		return _contextType.GetHashCode() ^ _code.GetHashCode()

class EvaluationScript:

	virtual def Run() as object:
		pass

class Evaluator:

	private static final TaintedAnnotation = object()

	static def Eval(context as EvaluationContext, code as string) as object:
		return Evaluator(context, code).Run()

	static def Taint(cu as Boo.Lang.Compiler.Ast.CompileUnit):
		cu[TaintedAnnotation] = TaintedAnnotation

	static def IsTainted(cu as Boo.Lang.Compiler.Ast.CompileUnit):
		return cu.ContainsAnnotation(TaintedAnnotation)

	_context as EvaluationContext
	_code as string
	_cacheKey as EvaluationScriptCacheKey
	_compilationResult as CompilerContext

	def constructor([required] context as EvaluationContext, [required] code as string):
		_context = context
		_code = code
		_cacheKey = EvaluationScriptCacheKey(context.GetType(), code)

	def Run():
		scriptType = CompileScript()
		script = ActivateScript(scriptType)
		return script.Run()

	def ActivateScript(scriptType as Type):
		script as EvaluationScript = scriptType(_context)
		_context.AddScript(script)
		return script

	private def CompileScript():

		type = GetCachedScript()
		if type is not null: return type

		type = DoCompile()
		CacheScript(type)
		return type

	private def GetCachedScript():
		return GetEvaluationDomain().GetCachedScript(_cacheKey)

	private def CacheScript(type as Type):
		if IsTainted(_compilationResult.CompileUnit): return
		GetEvaluationDomain().CacheScript(_cacheKey, type)

	private def GetEvaluationDomain():
		domain = _context.ScriptContainer.GetEvaluationDomain()
		assert domain is not null
		return domain

	private def DoCompile():

		compiler = UnityScriptCompiler()
		compiler.Parameters.Pipeline = AdjustPipeline(_context, UnityScriptCompiler.Pipelines.CompileToMemory())
		compiler.Parameters.ScriptBaseType = EvaluationScript
		compiler.Parameters.ScriptMainMethod = "Run"
		compiler.Parameters.Input.Add(StringInput("script", _code + ";"))
		compiler.Parameters.Debug = false
		compiler.Parameters.GenerateInMemory = true

		contextAssembly = _context.GetType().Assembly
		compiler.Parameters.References.Add(contextAssembly)
		for name in contextAssembly.GetReferencedAssemblies():
			compiler.Parameters.References.Add(System.Reflection.Assembly.Load(name))

		_compilationResult = compiler.Run()
		if len(_compilationResult.Errors):
			raise CompilationErrorsException(_compilationResult.Errors)

		//Console.Error.WriteLine(results.CompileUnit.ToCodeString())

		return _compilationResult.GeneratedAssembly.GetType("script")

	static def AdjustPipeline(context as EvaluationContext, pipeline as CompilerPipeline):
		pipeline.InsertAfter(
			UnityScript.Steps.IntroduceUnityGlobalNamespaces,
			UnityScript.Scripting.Pipeline.IntroduceScriptingNamespace(context))
		pipeline.InsertAfter(
			UnityScript.Scripting.Pipeline.IntroduceScriptingNamespace,
			UnityScript.Scripting.Pipeline.IntroduceImports(context))
		pipeline.InsertAfter(
			UnityScript.Steps.ApplySemantics,
			UnityScript.Scripting.Pipeline.IntroduceEvaluationContext(context))
		pipeline.Replace(
			UnityScript.Steps.ProcessUnityScriptMethods,
			UnityScript.Scripting.Pipeline.ProcessScriptingMethods(context))
		pipeline.InsertAfter(
			UnityScript.Scripting.Pipeline.ProcessScriptingMethods,
			UnityScript.Scripting.Pipeline.IntroduceReturnValue())
		return pipeline

namespace UnityScript.Scripting

import System
import UnityScript
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO

class CompilationErrorsException(Exception):

	[getter(Errors)]
	_errors as CompilerErrorCollection

	def constructor(errors as CompilerErrorCollection):
		super(errors.ToString(true))
		_errors = errors

interface IEvaluationDomainProvider:
"""
Every script in UnityScript defines a new EvaluationDomain.
"""
	def GetImports() as (string)
	def GetEvaluationDomain() as EvaluationDomain

class SimpleEvaluationDomainProvider(IEvaluationDomainProvider):
"""
SimpleEvaluationDomainProvider is used whenever there's an eval invocation
inside a static method.
"""
	private _domain = EvaluationDomain()
	private _imports as (string)

	def GetImports():
		return _imports

	def GetEvaluationDomain() as EvaluationDomain:
		return _domain

class EvaluationDomain:
"""
Groups together a set of related EvaluationScripts instances.
"""
	_cache = {}

	[lock]
	def GetCachedScript(key as EvaluationScriptCacheKey) as System.Type:
		return _cache[key]

	[lock]
	def CacheScript(key as EvaluationScriptCacheKey, type as System.Type):
		_cache[key] = type

class EvaluationScriptCacheKey:

	_contextType as System.Type
	_code as string

	def constructor(contextType as Type, code as string):
		_contextType = contextType
		_code = code

	override def Equals(o):
		other = o as EvaluationScriptCacheKey
		if other is null: return false
		return other._contextType is _contextType and other._code == _code

	override def GetHashCode():
		return _contextType.GetHashCode() ^ _code.GetHashCode()

class EvaluationScript:

	virtual def Run() as object:
		pass

class Evaluator:

	private static final TaintedAnnotation = object()

	static def Eval(context as EvaluationContext, code as string) as object:
		return Evaluator(context, code).Run()

	static def Taint(cu as Boo.Lang.Compiler.Ast.CompileUnit):
		cu[TaintedAnnotation] = TaintedAnnotation

	static def IsTainted(cu as Boo.Lang.Compiler.Ast.CompileUnit):
		return cu.ContainsAnnotation(TaintedAnnotation)

	_context as EvaluationContext
	_code as string
	_cacheKey as EvaluationScriptCacheKey
	_compilationResult as CompilerContext

	def constructor([required] context as EvaluationContext, [required] code as string):
		_context = context
		_code = code
		_cacheKey = EvaluationScriptCacheKey(context.GetType(), code)

	def Run():
		scriptType = CompileScript()
		script = ActivateScript(scriptType)
		return script.Run()

	def ActivateScript(scriptType as Type):
		script as EvaluationScript = scriptType(_context)
		_context.AddScript(script)
		return script

	private def CompileScript():

		type = GetCachedScript()
		if type is not null: return type

		type = DoCompile()
		CacheScript(type)
		return type

	private def GetCachedScript():
		return GetEvaluationDomain().GetCachedScript(_cacheKey)

	private def CacheScript(type as Type):
		if IsTainted(_compilationResult.CompileUnit): return
		GetEvaluationDomain().CacheScript(_cacheKey, type)

	private def GetEvaluationDomain():
		domain = _context.ScriptContainer.GetEvaluationDomain()
		assert domain is not null
		return domain

	private def DoCompile():

		compiler = UnityScriptCompiler()
		compiler.Parameters.Pipeline = AdjustPipeline(_context, UnityScriptCompiler.Pipelines.CompileToMemory())
		compiler.Parameters.ScriptBaseType = EvaluationScript
		compiler.Parameters.ScriptMainMethod = "Run"
		compiler.Parameters.Input.Add(StringInput("script", _code + ";"))

		contextAssembly = _context.GetType().Assembly
		compiler.Parameters.References.Add(contextAssembly)
		for name in contextAssembly.GetReferencedAssemblies():
			compiler.Parameters.References.Add(System.Reflection.Assembly.Load(name))

		_compilationResult = compiler.Run()
		if len(_compilationResult.Errors):
			raise CompilationErrorsException(_compilationResult.Errors)

		//Console.Error.WriteLine(results.CompileUnit.ToCodeString())

		return _compilationResult.GeneratedAssembly.GetType("script")

	static def AdjustPipeline(context as EvaluationContext, pipeline as CompilerPipeline):
		pipeline.InsertAfter(
			UnityScript.Steps.IntroduceUnityGlobalNamespaces,
			UnityScript.Scripting.Pipeline.IntroduceScriptingNamespace(context))
		pipeline.InsertAfter(
			UnityScript.Scripting.Pipeline.IntroduceScriptingNamespace,
			UnityScript.Scripting.Pipeline.IntroduceImports(context))
		pipeline.InsertAfter(
			UnityScript.Steps.ApplySemantics,
			UnityScript.Scripting.Pipeline.IntroduceEvaluationContext(context))
		pipeline.Replace(
			UnityScript.Steps.ProcessUnityScriptMethods,
			UnityScript.Scripting.Pipeline.ProcessScriptingMethods(context))
		pipeline.InsertAfter(
			UnityScript.Scripting.Pipeline.ProcessScriptingMethods,
			UnityScript.Scripting.Pipeline.IntroduceReturnValue())
		return pipeline


updated to be compatible with latest IQuackFu semantics

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

"""
This example shows how to use IQuackFu.QuackGet to provide
transparent access to xml elements.
"""

import System
import System.Xml from System.Xml
import System.Reflection

[DefaultMember("Item")]
class XmlObject(IQuackFu):

	_element as XmlElement

	def constructor(element as XmlElement):
		_element = element

	def constructor(text as string):
		doc = XmlDocument()
		doc.LoadXml(text)
		_element = doc.DocumentElement

	def QuackInvoke(name as string, args as (object)) as object:
		if name == "op_Addition":
			doc as XmlDocument = _element.ParentNode.CloneNode(true)
			tmp = XmlObject(doc.DocumentElement)
			docFrag = doc.CreateDocumentFragment()
			docFrag.InnerXml = args[1]
			tmp._element.AppendChild(docFrag)
			return tmp
		else:
			raise System.InvalidOperationException("Method ${name} not found in class ${self.GetType()}")

	def QuackSet(name as string, parameters as (object), value) as object:
		pass

	def QuackGet(name as string, parameters as (object)) as object:
		if name == "":
			assert len(parameters) == 1
			return GetAttribute(parameters[0])

		elements = _element.SelectNodes(name)
		if elements is not null:
			return XmlObject(elements[0]) if elements.Count == 1
			return XmlObject(e) for e in elements

	def GetAttribute(name as string):
		item = _element.Attributes.GetNamedItem(name)
		return item.InnerText if item

	override def ToString():
		return _element.InnerText

xml = """
<Person>
	<FirstName>John</FirstName>
	<LastName>Cleese</LastName>
	<Phone place="home">1111-111-111</Phone>
	<Phone place="work">2222-222-222</Phone>
</Person>
"""

person = XmlObject(xml)
print person.FirstName
print person.LastName
person += "<Phone place=\"cell\">3333-333-333</Phone>"
for phone as XmlObject in person.Phone:
	print phone['place'], phone

#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

"""
This example shows how to use IQuackFu.QuackGet to provide
transparent access to xml elements.
"""

import System
import System.Xml from System.Xml
import System.Reflection

[DefaultMember("Item")]
class XmlObject(IQuackFu):

	_element as XmlElement

	Item([required] key):
		get:
			item = _element.Attributes.GetNamedItem(key)
			return item.InnerText if item

	def constructor(element as XmlElement):
		_element = element

	def constructor(text as string):
		doc = XmlDocument()
		doc.LoadXml(text)
		_element = doc.DocumentElement

	def QuackInvoke(name as string, args as (object)) as object:
		if name == "op_Addition":
			doc as XmlDocument = _element.ParentNode.CloneNode(true)
			tmp = XmlObject(doc.DocumentElement)
			docFrag = doc.CreateDocumentFragment()
			docFrag.InnerXml = args[1]
			tmp._element.AppendChild(docFrag)
			return tmp
		else:
			raise System.InvalidOperationException("Method ${name} not found in class ${self.GetType()}")

	def QuackSet(name as string, parameters as (object), value) as object:
		pass

	def QuackGet(name as string, parameters as (object)) as object:
		assert parameters is null

		elements = _element.SelectNodes(name)
		if elements is not null:
			return XmlObject(elements[0]) if elements.Count == 1
			return XmlObject(e) for e in elements

	override def ToString():
		return _element.InnerText

xml = """
<Person>
	<FirstName>John</FirstName>
	<LastName>Cleese</LastName>
	<Phone place="home">1111-111-111</Phone>
	<Phone place="work">2222-222-222</Phone>
</Person>
"""

person as duck = XmlObject(xml)
print person.FirstName
print person.LastName
person += "<Phone place=\"cell\">3333-333-333</Phone>"
for phone as XmlObject in person.Phone:
	print phone['place'], phone


minor doc correction

minor doc correction

namespace Boo.Adt

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.PatternMatching

macro let:
"""
Declares a public static final field in the current scope.

Usage:

	let answer = 42
"""
	case [| let $name = $r |]:
		yield [|
			public static final $name = $r
		|]

namespace Boo.Adt

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.PatternMatching

macro let:
"""
Declares a public static final field in the current module.

Usage:

	let answer = 42
"""
	case [| let $name = $r |]:
		yield [|
			public static final $name = $r
		|]


string is also known as java.lang.String

namespace Boojay.Compilation.TypeSystem

import Boo.Lang.Compiler
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.TypeSystem.Reflection

class JavaReflectionTypeSystemProvider(ReflectionTypeSystemProvider):

	public static final SharedTypeSystemProvider = JavaReflectionTypeSystemProvider()

	def constructor():
		ReplaceMapping(System.String, JavaLangString)
		ReplaceMapping(java.lang.String, JavaLangString)
		ReplaceMapping(System.MulticastDelegate, Boojay.Lang.MulticastDelegate)
		ReplaceMapping(Boo.Lang.List, Boojay.Lang.List)
		ReplaceMapping(Boo.Lang.Hash, Boojay.Lang.Hash)
		ReplaceMapping(System.NotImplementedException, Boojay.Lang.NotImplementedException)

	override def CreateEntityForRegularType(type as System.Type):
		return BeanAwareType(self, type)

	def ReplaceMapping(existing as System.Type, new as System.Type):
		mapping = Map(new)
		MapTo(existing, mapping)
		return mapping

class JavaTypeSystem(TypeSystemServices):

	def constructor():
		self(CompilerContext())

	def constructor(context as CompilerContext):
		super(context)

	override ExceptionType:
		get: return Map(java.lang.Exception)

class JavaLangString(java.lang.Character*):

	self[index as int] as char:
		get: raise System.NotImplementedException()

	Length as int:
		get: raise System.NotImplementedException()

	def GetEnumerator():
		pass

	def System.Collections.IEnumerable.GetEnumerator():
		pass

	def toUpperCase():
		return self

	def toLowerCase():
		return self

	def trim():
		return self

	def toCharArray() as (char):
		return null

namespace Boojay.Compilation.TypeSystem

import Boo.Lang.Compiler
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.TypeSystem.Reflection

class JavaReflectionTypeSystemProvider(ReflectionTypeSystemProvider):

	public static final SharedTypeSystemProvider = JavaReflectionTypeSystemProvider()

	def constructor():
		ReplaceMapping(System.String, JavaLangString)
		ReplaceMapping(System.MulticastDelegate, Boojay.Lang.MulticastDelegate)
		ReplaceMapping(Boo.Lang.List, Boojay.Lang.List)
		ReplaceMapping(Boo.Lang.Hash, Boojay.Lang.Hash)
		ReplaceMapping(System.NotImplementedException, Boojay.Lang.NotImplementedException)

	override def CreateEntityForRegularType(type as System.Type):
		return BeanAwareType(self, type)

	def ReplaceMapping(existing as System.Type, new as System.Type):
		mapping = Map(new)
		MapTo(existing, mapping)
		return mapping

class JavaTypeSystem(TypeSystemServices):

	def constructor():
		self(CompilerContext())

	def constructor(context as CompilerContext):
		super(context)

	override ExceptionType:
		get: return Map(java.lang.Exception)

class JavaLangString(java.lang.Character*):

	self[index as int] as char:
		get: raise System.NotImplementedException()

	Length as int:
		get: raise System.NotImplementedException()

	def GetEnumerator():
		pass

	def System.Collections.IEnumerable.GetEnumerator():
		pass

	def toUpperCase():
		return self

	def toLowerCase():
		return self

	def trim():
		return self

	def toCharArray() as (char):
		return null


saner indentation

saner indentation

namespace Boo.Adt.Tests

import NUnit.Framework
import Boo.Adt

data GExpression[T] = GConst(value as T) \
	| GAdd(left as GExpression[of T], right as GExpression[of T])

[TestFixture]
class GenericDataMacroTest:

	[Test]
	def TestClassHierarchy():
		type = GExpression[of int]
		assert type.IsAbstract

		for type in GConst[of int], GAdd[of int]:
			assert not type.IsAbstract
			assert not type.IsSealed

	[Test]
	def TestToString():
		Assert.AreEqual("GConst(42)", GConst[of int](42).ToString())
		Assert.AreEqual("GAdd(GConst(19), GConst(22))", GAdd[of int](GConst[of int](19), GConst[of int](22)).ToString())

	[Test]
	def TestEquals():
		Assert.AreEqual(GConst[of int](42), GConst[of int](42))
		assert GConst[of int](-1) != GConst[of int](42)

	[Test]
	def TestProperties():
		Assert.AreEqual(42, GConst[of int](42).value)