updated booxw to the latest api but unfortunately the compiler is failing to add the resources to application

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

#region license
// Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
// All rights reserved.
//
// This file is part of Boo Explorer.
//
// Boo Explorer 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 BooExplorer

import WeifenLuo.WinFormsUI
import System
import System.IO
import System.Windows.Forms
import System.Drawing
import Boo.Lang.Compiler.Ast

enum TypeIcon:

	Namespace
	PublicClass
	PublicInterface
	PublicEnum
	PublicField
	PublicProperty
	PublicMethod
	InternalClass
	InternalInterface
	InternalEnum
	InternalField
	InternalProperty
	InternalMethod
	ProtectedClass
	ProtectedInterface
	ProtectedEnum
	ProtectedField
	ProtectedProperty
	ProtectedMethod
	PrivateClass
	PrivateInterface
	PrivateEnum
	PrivateField
	PrivateProperty
	PrivateMethod
	PublicEvent

class TypeIconChooser:

	static def GetPropertyIcon(node as Property, inInterface as bool) as int:
		return cast(int, TypeIcon.PublicProperty) if inInterface
		if node.IsVisibilitySet:
			if node.IsInternal:
				return cast(int, TypeIcon.InternalProperty)
			if node.IsProtected:
				return cast(int, TypeIcon.ProtectedProperty)
			if node.IsPrivate:
				return cast(int, TypeIcon.PrivateProperty)

		return cast(int, TypeIcon.PublicProperty)

	static def GetFieldIcon(node as Field) as int:
		if node.IsVisibilitySet:
			if node.IsInternal:
				return cast(int, TypeIcon.InternalField)
			if node.IsPublic:
				return cast(int, TypeIcon.PublicField)
			if node.IsPrivate:
				return cast(int, TypeIcon.PrivateField)

		return cast(int, TypeIcon.ProtectedField)

class BooxImageList:

	static _imageList as ImageList

	static Instance as ImageList:
		get:
			if _imageList is null:
				_imageList = ImageList()
				_imageList.ImageStream = System.Resources.ResourceManager(DocumentOutline).GetObject("_imageList")
			return _imageList

class DocumentOutline(DockContent):

	_activeDocument as BooEditor
	_tree as TreeView
	_treeViewVisitor as TreeViewVisitor
	_timer = Timer(Tick: _timer_Tick, Interval: 3s.TotalMilliseconds)
	_module as Module

	def constructor():
		InitTreeView()

		_treeViewVisitor = TreeViewVisitor(_tree)

		SuspendLayout()

		Controls.Add(_tree)
		self.DockableAreas = (
					DockAreas.Float |
					DockAreas.DockLeft |
					DockAreas.DockRight)
		self.ClientSize = System.Drawing.Size(295, 347)

		self.DockPadding.Bottom = 2
		self.DockPadding.Top = 26
		self.ShowHint = DockState.DockRight;
		self.Text = "Document Outline"
		self.HideOnClose = true
		ResumeLayout(false)

	def InitTreeView():
		_tree = TreeView(Dock: DockStyle.Fill,
						DoubleClick: _tree_DoubleClick,
						ImageIndex: cast(int, TypeIcon.Namespace),
						SelectedImageIndex: cast(int, TypeIcon.Namespace),
						ImageList: BooxImageList.Instance,
						Sorted: true)

	ActiveDocument as BooEditor:
		set:
			_activeDocument = value
			_timer.Enabled = value is not null
			Update() if self.Visible

	def Update():
		if _activeDocument is null:
			_tree.Nodes.Clear()
		else:
			_activeDocument.UpdateModule()
			UpdateTree(_activeDocument.Module)

	def UpdateTree(module as Module):
		if module is not _module:
			_module = module
			_treeViewVisitor.Visit(_module)

	def GoToNode([required] treeNode as TreeNode):
		return unless _activeDocument
		node as Node = treeNode.Tag
		if node is not null:
			info = node.LexicalInfo
			_activeDocument.GoTo(info.Line-1)

	def _timer_Tick(sender, args as EventArgs):
		Update()

	def _tree_DoubleClick(sender, args as EventArgs):

		if (treeNode = _tree.SelectedNode) is not null:
			GoToNode(treeNode)

	override protected def GetPersistString():
		return "DocumentOutline|"

class TreeViewVisitor(DepthFirstVisitor):

	_tree as TreeView
	_current as TreeNode
	_inInterface as bool

	def constructor(tree):
		_tree = tree

	override def OnModule(node as Module):

		_current = TreeNode("root")
		VisitCollection(node.Members)

		_tree.BeginUpdate()

		//state = SaveTreeViewState() if len(_current.Nodes)
		_tree.Nodes.Clear()
		if len(_current.Nodes):
			_tree.Nodes.AddRange(array(TreeNode, _current.Nodes))
			_tree.ExpandAll()
			//RestoreTreeViewState(state) if len(state)
		_tree.EndUpdate()

	override def OnProperty(node as Property):
		Add(node.Name, TypeIconChooser.GetPropertyIcon(node, _inInterface), node)

	override def OnField(node as Field):
		Add(node.Name, TypeIconChooser.GetFieldIcon(node), node)

	override def OnEvent(node as Event):
		Add(node.Name, cast(int, TypeIcon.PublicEvent), node)

	override def OnInterfaceDefinition(node as InterfaceDefinition):
		OnTypeDefinition(node, cast(int, TypeIcon.PublicInterface))

	override def OnClassDefinition(node as ClassDefinition):
		OnTypeDefinition(node, cast(int, TypeIcon.PublicClass))

	override def OnEnumDefinition(node as EnumDefinition):
		OnTypeDefinition(node, cast(int, TypeIcon.PublicEnum))

	override def OnEnumMember(node as EnumMember):
		Add(node.Name, cast(int, TypeIcon.PublicField), node)

	def OnTypeDefinition(node as TypeDefinition, imageIndex as int):
		_inInterface = node isa InterfaceDefinition
		saved = _current

		_current = Add(node.Name, imageIndex, imageIndex, node)
		VisitCollection(node.Members)

		_current = saved

	override def OnConstructor(node as Constructor):
		OnMethod(node)

	override def OnMethod(node as Method):
		name = "${node.Name}(${join([p.Name for p as ParameterDeclaration in node.Parameters], ', ')})"
		Add(name, cast(int, TypeIcon.PublicMethod), node)

	def Add(text as string, data):
		node = _current.Nodes.Add(text)
		node.Tag = data
		return node

	def Add(text as string, imageIndex as int, data):
		Add(text, imageIndex, imageIndex, data)

	def Add(text as string, imageIndex as int, selectedImageIndex as int, data):
		node = _current.Nodes.Add(text)
		node.Tag = data
		node.ImageIndex = imageIndex
		node.SelectedImageIndex = selectedImageIndex
		return node

	def SaveTreeViewState():
		return SaveTreeViewState([], _tree.Nodes)

	def SaveTreeViewState(state as List, nodes as TreeNodeCollection):
		for node as TreeNode in nodes:
			SaveTreeViewState(state, node)
		return state

	def SaveTreeViewState(state as List, node as TreeNode):
		if len(node.Nodes):
			state.Add((node.FullPath, node.IsExpanded))
			SaveTreeViewState(state, node.Nodes)

	def RestoreTreeViewState(state):
		for fullpath as string, expanded as bool in state:
			if not expanded:
				node = SelectNode(fullpath)
				node.Collapse() if node

	def SelectNode(fullpath as string):
		parts = /\//.Split(fullpath)

		nodes = _tree.Nodes
		for part in parts:
			node = SelectNode(nodes, part)
			break if node is null
			nodes = node.Nodes

		return node

	def SelectNode(nodes as TreeNodeCollection, text as string):
		for node as TreeNode in nodes:
			if node.Text == text:
				return node
		return null

#region license
// Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
// All rights reserved.
//
// This file is part of Boo Explorer.
//
// Boo Explorer 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 BooExplorer

import WeifenLuo.WinFormsUI
import System
import System.IO
import System.Windows.Forms
import System.Drawing
import Boo.Lang.Compiler.Ast

enum TypeIcon:

	Namespace
	PublicClass
	PublicInterface
	PublicEnum
	PublicField
	PublicProperty
	PublicMethod
	InternalClass
	InternalInterface
	InternalEnum
	InternalField
	InternalProperty
	InternalMethod
	ProtectedClass
	ProtectedInterface
	ProtectedEnum
	ProtectedField
	ProtectedProperty
	ProtectedMethod
	PrivateClass
	PrivateInterface
	PrivateEnum
	PrivateField
	PrivateProperty
	PrivateMethod
	PublicEvent

class TypeIconChooser:

	static def GetPropertyIcon(node as Property, inInterface as bool) as int:
		return cast(int, TypeIcon.PublicProperty) if inInterface
		if node.IsVisibilitySet:
			if node.IsInternal:
				return cast(int, TypeIcon.InternalProperty)
			if node.IsProtected:
				return cast(int, TypeIcon.ProtectedProperty)
			if node.IsPrivate:
				return cast(int, TypeIcon.PrivateProperty)

		return cast(int, TypeIcon.PublicProperty)

	static def GetFieldIcon(node as Field) as int:
		if node.IsVisibilitySet:
			if node.IsInternal:
				return cast(int, TypeIcon.InternalField)
			if node.IsPublic:
				return cast(int, TypeIcon.PublicField)
			if node.IsPrivate:
				return cast(int, TypeIcon.PrivateField)

		return cast(int, TypeIcon.ProtectedField)

class BooxImageList:

	static _imageList as ImageList

	static Instance as ImageList:
		get:
			if _imageList is null:
				_imageList = ImageList()
				_imageList.ImageStream = System.Resources.ResourceManager(DocumentOutline).GetObject("_imageList")
			return _imageList

class DocumentOutline(DockContent):

	_activeDocument as BooEditor
	_tree as TreeView
	_treeViewVisitor as TreeViewVisitor
	_timer = Timer(Tick: _timer_Tick, Interval: 3s.TotalMilliseconds)
	_module as Module

	def constructor():
		InitTreeView()

		_treeViewVisitor = TreeViewVisitor(_tree)

		SuspendLayout()

		Controls.Add(_tree)
		self.DockableAreas = (
					DockAreas.Float |
					DockAreas.DockLeft |
					DockAreas.DockRight)
		self.ClientSize = System.Drawing.Size(295, 347)

		self.DockPadding.Bottom = 2
		self.DockPadding.Top = 26
		self.ShowHint = DockState.DockRight;
		self.Text = "Document Outline"
		self.HideOnClose = true
		ResumeLayout(false)

	def InitTreeView():
		_tree = TreeView(Dock: DockStyle.Fill,
						DoubleClick: _tree_DoubleClick,
						ImageIndex: cast(int, TypeIcon.Namespace),
						SelectedImageIndex: cast(int, TypeIcon.Namespace),
						ImageList: BooxImageList.Instance,
						Sorted: true)

	ActiveDocument as BooEditor:
		set:
			_activeDocument = value
			_timer.Enabled = value is not null
			Update() if self.Visible

	def Update():
		if _activeDocument is null:
			_tree.Nodes.Clear()
		else:
			_activeDocument.UpdateModule()
			UpdateTree(_activeDocument.Module)

	def UpdateTree(module as Module):
		if module is not _module:
			_module = module
			_treeViewVisitor.Visit(_module)

	def GoToNode([required] treeNode as TreeNode):
		return unless _activeDocument
		node as Node = treeNode.Tag
		if node is not null:
			info = node.LexicalInfo
			_activeDocument.GoTo(info.Line-1)

	def _timer_Tick(sender, args as EventArgs):
		Update()

	def _tree_DoubleClick(sender, args as EventArgs):

		if (treeNode = _tree.SelectedNode) is not null:
			GoToNode(treeNode)

	override protected def GetPersistString():
		return "DocumentOutline|"

class TreeViewVisitor(DepthFirstVisitor):

	_tree as TreeView
	_current as TreeNode
	_inInterface as bool

	def constructor(tree):
		_tree = tree

	override def OnModule(node as Module):

		_current = TreeNode("root")
		Visit(node.Members)

		_tree.BeginUpdate()

		//state = SaveTreeViewState() if len(_current.Nodes)
		_tree.Nodes.Clear()
		if len(_current.Nodes):
			_tree.Nodes.AddRange(array(TreeNode, _current.Nodes))
			_tree.ExpandAll()
			//RestoreTreeViewState(state) if len(state)
		_tree.EndUpdate()

	override def OnProperty(node as Property):
		Add(node.Name, TypeIconChooser.GetPropertyIcon(node, _inInterface), node)

	override def OnField(node as Field):
		Add(node.Name, TypeIconChooser.GetFieldIcon(node), node)

	override def OnEvent(node as Event):
		Add(node.Name, cast(int, TypeIcon.PublicEvent), node)

	override def OnInterfaceDefinition(node as InterfaceDefinition):
		OnTypeDefinition(node, cast(int, TypeIcon.PublicInterface))

	override def OnClassDefinition(node as ClassDefinition):
		OnTypeDefinition(node, cast(int, TypeIcon.PublicClass))

	override def OnEnumDefinition(node as EnumDefinition):
		OnTypeDefinition(node, cast(int, TypeIcon.PublicEnum))

	override def OnEnumMember(node as EnumMember):
		Add(node.Name, cast(int, TypeIcon.PublicField), node)

	def OnTypeDefinition(node as TypeDefinition, imageIndex as int):
		_inInterface = node isa InterfaceDefinition
		saved = _current

		_current = Add(node.Name, imageIndex, imageIndex, node)
		Visit(node.Members)

		_current = saved

	override def OnConstructor(node as Constructor):
		OnMethod(node)

	override def OnMethod(node as Method):
		name = "${node.Name}(${join([p.Name for p as ParameterDeclaration in node.Parameters], ', ')})"
		Add(name, cast(int, TypeIcon.PublicMethod), node)

	def Add(text as string, data):
		node = _current.Nodes.Add(text)
		node.Tag = data
		return node

	def Add(text as string, imageIndex as int, data):
		Add(text, imageIndex, imageIndex, data)

	def Add(text as string, imageIndex as int, selectedImageIndex as int, data):
		node = _current.Nodes.Add(text)
		node.Tag = data
		node.ImageIndex = imageIndex
		node.SelectedImageIndex = selectedImageIndex
		return node

	def SaveTreeViewState():
		return SaveTreeViewState([], _tree.Nodes)

	def SaveTreeViewState(state as List, nodes as TreeNodeCollection):
		for node in nodes:
			SaveTreeViewState(state, node)
		return state

	def SaveTreeViewState(state as List, node as TreeNode):
		if len(node.Nodes):
			state.Add((node.FullPath, node.IsExpanded))
			SaveTreeViewState(state, node.Nodes)

	def RestoreTreeViewState(state):
		for fullpath as string, expanded as bool in state:
			if not expanded:
				node = SelectNode(fullpath)
				node.Collapse() if node

	def SelectNode(fullpath as string):
		parts = /\//.Split(fullpath)

		nodes = _tree.Nodes
		for part in parts:
			node = SelectNode(nodes, part)
			break if node is null
			nodes = node.Nodes

		return node

	def SelectNode(nodes as TreeNodeCollection, text as string):
		for node as TreeNode in nodes:
			if node.Text == text:
				return node
		return null


usage information

usage information

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

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

namespace Boo.Lang.Useful.Attributes

import System.Threading
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps
import Boo.Lang.Compiler.TypeSystem

class OnceAttribute(AbstractAstAttribute):
"""
Caches the return value of a method.

Usage
	[once]
	def foo():
		return Math.Sin(Math.PI*3)

@author Sorin Ionescu (sorin.ionescu@gmail.com)
"""
	private class ReturnValueStorageVisitor(DepthFirstVisitor):
	"""
	Replaces returns statements with binary expressions that
	store the values of the return statements.
	"""
		_returnValue as ReferenceExpression

		def constructor(returnValue as ReferenceExpression):
			_returnValue = returnValue

		override def OnReturnStatement(returnStatement as ReturnStatement):
		"""
		Replaces returns statements with binary expressions that
		store the values of the return statements.
		"""
			returnValueAssignment = BinaryExpression(
				LexicalInfo: returnStatement.LexicalInfo,
				Operator: BinaryOperatorType.Assign,
				Left: _returnValue,
				Right: returnStatement.Expression)

			parentNode = returnStatement.ParentNode
			parentNode.Replace(
				returnStatement,
				ExpressionStatement(returnValueAssignment))

	_method as Method
	_methodLock as Field
	_cached as Field
	_returnValue as Field

	override def Dispose():
	"""
	Dont get rid of the context because we'll need it later.
	"""
		pass

	override def Apply(node as Node):
	"""
	Applies the <OnceAttribute> to [node].

	Parameters:
		node
			The node to apply the <OnceAttribute> to.
	"""
		assert node isa Method

		_method = node

		CreateCachedField()
		CreateMethodLockField()
		PrepareMethodBody()

		Context.Parameters.Pipeline.AfterStep += def(
			sender,
			e as CompilerStepEventArgs):

			return if not e.Step isa ProcessMethodBodies

			# Void methods cannot be cached.
			assert _method.ReturnType.Entity is not \
				self.TypeSystemServices.VoidType, "once attribute cannot be applied to void methods"

			CreateReturnValueField()
			PostProcessMethod()

	def CreateReturnValueField():
	"""
	Creates the field that stores the return value of the cached method.
	"""
		template = self.CodeBuilder.CreateField('field', _method.ReturnType.Entity)
		_returnValue = AddField(template, "___${_method.Name}_returnValue")

	def CreateCachedField():
	"""
	Creates the cached flag.

	Remarks:
		The flag is used to check whether the method has been cached.
	"""
		template = ast:
			private field as bool
		_cached = AddField(template, "___${_method.Name}_cached")

	def CreateMethodLockField():
	"""
	Creates the lock field.

	Remarks:
		The field is used to lock on when the operatation is thread safe.
	"""
		template = ast:
			private field as object = object()
		_methodLock = AddField(template, "___${_method.Name}_lock")

	def AddField(template as Field, name as string):
		template.LexicalInfo = self.LexicalInfo
		template.Name = name
		template.Modifiers = TypeMemberModifiers.Private
		template.Modifiers |= TypeMemberModifiers.Static if IsStaticMethod()
		_method.DeclaringType.Members.Add(template)
		return template

	def IsStaticMethod():
		return _method.IsStatic or _method.ParentNode isa Module

	def PrepareMethodBody():
		newMethodBodyTemplate = ast:
			if not cached:
				System.Threading.Monitor.Enter(methodLock)
				try:
					if not cached:
						oldMethodBody
						cached = true
				ensure:
					System.Threading.Monitor.Exit(methodLock)

		ReplaceReferences(newMethodBodyTemplate, 'cached', _cached.Name)
		ReplaceReferences(newMethodBodyTemplate, 'methodLock', _methodLock.Name)
		newMethodBodyTemplate.ReplaceNodes(
			MacroStatement(Name: 'oldMethodBody'),
			_method.Body)

		_method.Body = Block()
		_method.Body.Add(newMethodBodyTemplate)

	def ReplaceReferences(node as Node, what as string, value as string):
		node.ReplaceNodes(
			ReferenceExpression(what),
			ReferenceExpression(value))

	def PostProcessMethod():
	"""
	Visit the node and replace return statements
	with binary expressions that store the return
	statement values.
	Add a single return statement at the end
	to return the cached value.
	"""
		_method.Accept(
				ReturnValueStorageVisitor(
					self.CodeBuilder.CreateReference(_returnValue)))
		_method.Body.Add(
			ReturnStatement(
				LexicalInfo: LexicalInfo,
				Expression: self.CodeBuilder.CreateReference(_returnValue)))

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

namespace Boo.Lang.Useful.Attributes

import System.Threading
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps
import Boo.Lang.Compiler.TypeSystem

class OnceAttribute(AbstractAstAttribute):
"""
Caches the return value of a method.

@author Sorin Ionescu (sorin.ionescu@gmail.com)
"""
	private class ReturnValueStorageVisitor(DepthFirstVisitor):
	"""
	Replaces returns statements with binary expressions that
	store the values of the return statements.
	"""
		_returnValue as ReferenceExpression

		def constructor(returnValue as ReferenceExpression):
			_returnValue = returnValue

		override def OnReturnStatement(returnStatement as ReturnStatement):
		"""
		Replaces returns statements with binary expressions that
		store the values of the return statements.
		"""
			returnValueAssignment = BinaryExpression(
				LexicalInfo: returnStatement.LexicalInfo,
				Operator: BinaryOperatorType.Assign,
				Left: _returnValue,
				Right: returnStatement.Expression)

			parentNode = returnStatement.ParentNode
			parentNode.Replace(
				returnStatement,
				ExpressionStatement(returnValueAssignment))

	_method as Method
	_methodLock as Field
	_cached as Field
	_returnValue as Field

	override def Dispose():
	"""
	Dont get rid of the context because we'll need it later.
	"""
		pass

	override def Apply(node as Node):
	"""
	Applies the <OnceAttribute> to [node].

	Parameters:
		node
			The node to apply the <OnceAttribute> to.
	"""
		assert node isa Method

		_method = node

		CreateCachedField()
		CreateMethodLockField()
		PrepareMethodBody()

		Context.Parameters.Pipeline.AfterStep += def(
			sender,
			e as CompilerStepEventArgs):

			return if not e.Step isa ProcessMethodBodies

			# Void methods cannot be cached.
			assert _method.ReturnType.Entity is not \
				self.TypeSystemServices.VoidType, "once attribute cannot be applied to void methods"

			CreateReturnValueField()
			PostProcessMethod()

	def CreateReturnValueField():
	"""
	Creates the field that stores the return value of the cached method.
	"""
		template = self.CodeBuilder.CreateField('field', _method.ReturnType.Entity)
		_returnValue = AddField(template, "___${_method.Name}_returnValue")

	def CreateCachedField():
	"""
	Creates the cached flag.

	Remarks:
		The flag is used to check whether the method has been cached.
	"""
		template = ast:
			private field as bool
		_cached = AddField(template, "___${_method.Name}_cached")

	def CreateMethodLockField():
	"""
	Creates the lock field.

	Remarks:
		The field is used to lock on when the operatation is thread safe.
	"""
		template = ast:
			private field as object = object()
		_methodLock = AddField(template, "___${_method.Name}_lock")

	def AddField(template as Field, name as string):
		template.LexicalInfo = self.LexicalInfo
		template.Name = name
		template.Modifiers = TypeMemberModifiers.Private
		template.Modifiers |= TypeMemberModifiers.Static if IsStaticMethod()
		_method.DeclaringType.Members.Add(template)
		return template

	def IsStaticMethod():
		return _method.IsStatic or _method.ParentNode isa Module

	def PrepareMethodBody():
		newMethodBodyTemplate = ast:
			if not cached:
				System.Threading.Monitor.Enter(methodLock)
				try:
					if not cached:
						oldMethodBody
						cached = true
				ensure:
					System.Threading.Monitor.Exit(methodLock)

		ReplaceReferences(newMethodBodyTemplate, 'cached', _cached.Name)
		ReplaceReferences(newMethodBodyTemplate, 'methodLock', _methodLock.Name)
		newMethodBodyTemplate.ReplaceNodes(
			MacroStatement(Name: 'oldMethodBody'),
			_method.Body)

		_method.Body = Block()
		_method.Body.Add(newMethodBodyTemplate)

	def ReplaceReferences(node as Node, what as string, value as string):
		node.ReplaceNodes(
			ReferenceExpression(what),
			ReferenceExpression(value))

	def PostProcessMethod():
	"""
	Visit the node and replace return statements
	with binary expressions that store the return
	statement values.
	Add a single return statement at the end
	to return the cached value.
	"""
		_method.Accept(
				ReturnValueStorageVisitor(
					self.CodeBuilder.CreateReference(_returnValue)))
		_method.Body.Add(
			ReturnStatement(
				LexicalInfo: LexicalInfo,
				Expression: self.CodeBuilder.CreateReference(_returnValue)))


support for matching TryCastExpression and MethodInvocationExpression

namespace Boo.PatternMatching

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

# TODO: check for unreacheable patterns
class MatchMacro(AbstractAstMacro):
"""
Pattern matching facility:

	match <expression>:
		case <Pattern1>:
			<block1>
			.
			.
			.
		case <PatternN>:
			<blockN>
		otherwise:
			<blockOtherwise>

The following patterns are supported:

    Type() -- type test pattern
    Type(Property1: Pattern1, ...) -- object pattern
    Pattern1 | Pattern2 -- either pattern (NOT IMPLEMENTED)
    Pattern1 and condition -- constrained pattern  (NOT IMPLEMENTED)
    Pattern1 or condition -- constrained pattern  (NOT IMPLEMENTED)
    (Pattern1, Pattern2) -- fixed size iteration pattern
    [Pattern1, Pattern2] -- arbitrary size iteration pattern (NOT IMPLEMENTED)
    x = Pattern -- variable binding
    x -- variable binding
    BinaryOperatorType.Assign -- constant pattern
    42 -- constant pattern
    "42" -- constant pattern
    null -- null test pattern

If no pattern matches MatchError is raised.
"""
	override def Expand(node as MacroStatement):
		assert 0 == len(node.Block.Statements)
		return MatchExpansion(Context, node).value

class MatchExpansion:

	node as MacroStatement
	expression as Expression
	context as CompilerContext
	public final value as Statement

	def constructor(context as CompilerContext, node as MacroStatement):
		self.context = context
		self.node = node
		self.expression = node.Arguments[0]
		self.value = expand(newTemp(expression))

	def expand(matchValue as Expression):

		topLevel = expanded = expandCase(matchValue, caseList(node)[0])
		for case in caseList(node)[1:]:
			caseExpansion = expandCase(matchValue, case)
			expanded.FalseBlock = caseExpansion.ToBlock()
			expanded = caseExpansion
		expanded.FalseBlock = expandOtherwise(matchValue)

		return [|
			block:
				$matchValue = $expression
				$topLevel
		|].Block

	def expandOtherwise(matchValue as Expression):
		otherwise as MacroStatement = node["otherwise"]
		if otherwise is null: return defaultOtherwise(matchValue)
		return expandOtherwise(otherwise)

	def expandOtherwise(node as MacroStatement):
		assert 0 == len(node.Arguments)
		return node.Block

	def defaultOtherwise(matchValue as Expression):
		matchError = [| raise MatchError("'" + $(expression.ToCodeString()) + "' failed to match '" + $matchValue + "'") |]
		matchError.LexicalInfo = node.LexicalInfo
		return matchError.ToBlock()

	def expandCase(matchValue as Expression, node as MacroStatement):
		assert 1 == len(node.Arguments)
		pattern = node.Arguments[0]
		condition = expandPattern(matchValue, pattern)
		return [|
			if $condition:
				$(node.Block)
		|]

	def expandPattern(matchValue as Expression, pattern as Expression) as Expression:
		mie = pattern as MethodInvocationExpression
		if mie is not null:
			return expandObjectPattern(matchValue, mie)

		memberRef = pattern as MemberReferenceExpression
		if memberRef is not null:
			return expandValuePattern(matchValue, memberRef)

		reference = pattern as ReferenceExpression
		if reference is not null:
			return expandBindPattern(matchValue, reference)

		quasiquote = pattern as QuasiquoteExpression
		if quasiquote is not null:
			return expandQuasiquotePattern(matchValue, quasiquote)

		capture = pattern as BinaryExpression
		if isCapture(capture):
			return expandCapturePattern(matchValue, capture)

		fixedSize = pattern as ArrayLiteralExpression
		if fixedSize is not null:
			return expandFixedSizePattern(matchValue, fixedSize)

		return expandValuePattern(matchValue, pattern)

	def isCapture(node as BinaryExpression):
		if node is null: return false
		if node.Operator != BinaryOperatorType.Assign: return false
		return node.Left isa ReferenceExpression and node.Right isa MethodInvocationExpression

	def expandBindPattern(matchValue as Expression, node as ReferenceExpression):
		return [| __eval__($node = $matchValue, true) |]

	def expandValuePattern(matchValue as Expression, node as Expression):
		return [| $matchValue == $node |]

	def expandCapturePattern(matchValue as Expression, node as BinaryExpression):
		return expandObjectPattern(matchValue, node.Left, node.Right)

	def expandObjectPattern(matchValue as Expression, node as MethodInvocationExpression) as Expression:

		if len(node.NamedArguments) == 0 and len(node.Arguments) == 0:
			return [| $matchValue isa $(typeRef(node)) |]

		return expandObjectPattern(matchValue, newTemp(node), node)

	def expandObjectPattern(matchValue as Expression, temp as ReferenceExpression, node as MethodInvocationExpression) as Expression:

		condition = [| ($matchValue isa $(typeRef(node))) and __eval__($temp = cast($(typeRef(node)), $matchValue), true) |]
		condition.LexicalInfo = node.LexicalInfo

		for member in node.Arguments:
			assert member isa ReferenceExpression, "Invalid argument '${member}' in pattern '${node}'."
			memberRef = MemberReferenceExpression(member.LexicalInfo, temp.CloneNode(), member.ToString())
			condition = [| $condition and __eval__($member = $memberRef, true) |]

		for member in node.NamedArguments:
			namedArgCondition = expandMemberPattern(temp.CloneNode(), member)
			condition = [| $condition and $namedArgCondition |]

		return condition

	class QuasiquotePatternBuilder(DepthFirstVisitor):

		_expansion as MatchExpansion
		_pattern as Expression

		def constructor(expansion as MatchExpansion):
			_expansion = expansion

		def build(node as QuasiquoteExpression):
			return expand(node.Node)

		def expand(node as Node):
			node.Accept(self)
			expansion = _pattern
			_pattern = null
			assert expansion is not null, "Unsupported pattern '${node}'"
			return expansion

		override def OnSpliceExpression(node as SpliceExpression):
			_pattern = node.Expression

		override def OnSpliceTypeReference(node as SpliceTypeReference):
			_pattern = node.Expression

		override def OnTryCastExpression(node as TryCastExpression):
			_pattern = [| TryCastExpression(Target: $(expand(node.Target)), Type: $(expand(node.Type))) |]

		override def OnMethodInvocationExpression(node as MethodInvocationExpression):
			assert 0 == len(node.Arguments), "Unsupported pattern '${node}'"
			_pattern = [| MethodInvocationExpression(Target: $(expand(node.Target))) |]

		override def OnUnaryExpression(node as UnaryExpression):
			_pattern = [| UnaryExpression(Operator: UnaryOperatorType.$(node.Operator.ToString()), Operand: $(expand(node.Operand))) |]

		override def OnBinaryExpression(node as BinaryExpression):
			_pattern = [| BinaryExpression(Operator: BinaryOperatorType.$(node.Operator.ToString()), Left: $(expand(node.Left)), Right: $(expand(node.Right))) |]

		override def OnReferenceExpression(node as ReferenceExpression):
			_pattern = [| ReferenceExpression(Name: $(node.Name)) |]

	def objectPatternFor(node as QuasiquoteExpression):
		return QuasiquotePatternBuilder(self).build(node)

	def expandQuasiquotePattern(matchValue as Expression, node as QuasiquoteExpression) as Expression:
		return expandObjectPattern(matchValue, objectPatternFor(node))

	def expandMemberPattern(matchValue as Expression, member as ExpressionPair):
		memberRef = MemberReferenceExpression(member.First.LexicalInfo, matchValue, member.First.ToString())
		return expandPattern(memberRef, member.Second)

	def expandFixedSizePattern(matchValue as Expression, pattern as ArrayLiteralExpression):
		condition = [| $(len(pattern.Items)) == len($matchValue) |]
		i = 0
		for item in pattern.Items:
			itemValue = [| $matchValue[$i] |]
			itemPattern = expandPattern(itemValue, item)
			condition = [| $condition and $itemPattern |]
			++i
		return condition

	def typeRef(node as MethodInvocationExpression):
		return node.Target

	def newTemp(e as Expression):
		return ReferenceExpression(
				LexicalInfo: e.LexicalInfo,
				Name: "$match$${context.AllocIndex()}")

namespace Boo.PatternMatching

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

# TODO: check for unreacheable patterns
class MatchMacro(AbstractAstMacro):
"""
Pattern matching facility:

	match <expression>:
		case <Pattern1>:
			<block1>
			.
			.
			.
		case <PatternN>:
			<blockN>
		otherwise:
			<blockOtherwise>

The following patterns are supported:

    Type() -- type test pattern
    Type(Property1: Pattern1, ...) -- object pattern
    Pattern1 | Pattern2 -- either pattern (NOT IMPLEMENTED)
    Pattern1 and condition -- constrained pattern  (NOT IMPLEMENTED)
    Pattern1 or condition -- constrained pattern  (NOT IMPLEMENTED)
    (Pattern1, Pattern2) -- fixed size iteration pattern
    [Pattern1, Pattern2] -- arbitrary size iteration pattern (NOT IMPLEMENTED)
    x = Pattern -- variable binding
    x -- variable binding
    BinaryOperatorType.Assign -- constant pattern
    42 -- constant pattern
    "42" -- constant pattern
    null -- null test pattern

If no pattern matches MatchError is raised.
"""
	override def Expand(node as MacroStatement):
		assert 0 == len(node.Block.Statements)
		return MatchExpansion(Context, node).value

class MatchExpansion:

	node as MacroStatement
	expression as Expression
	context as CompilerContext
	public final value as Statement

	def constructor(context as CompilerContext, node as MacroStatement):
		self.context = context
		self.node = node
		self.expression = node.Arguments[0]
		self.value = expand(newTemp(expression))

	def expand(matchValue as Expression):

		topLevel = expanded = expandCase(matchValue, caseList(node)[0])
		for case in caseList(node)[1:]:
			caseExpansion = expandCase(matchValue, case)
			expanded.FalseBlock = caseExpansion.ToBlock()
			expanded = caseExpansion
		expanded.FalseBlock = expandOtherwise(matchValue)

		return [|
			block:
				$matchValue = $expression
				$topLevel
		|].Block

	def expandOtherwise(matchValue as Expression):
		otherwise as MacroStatement = node["otherwise"]
		if otherwise is null: return defaultOtherwise(matchValue)
		return expandOtherwise(otherwise)

	def expandOtherwise(node as MacroStatement):
		assert 0 == len(node.Arguments)
		return node.Block

	def defaultOtherwise(matchValue as Expression):
		matchError = [| raise MatchError("'" + $(expression.ToCodeString()) + "' failed to match '" + $matchValue + "'") |]
		matchError.LexicalInfo = node.LexicalInfo
		return matchError.ToBlock()

	def expandCase(matchValue as Expression, node as MacroStatement):
		assert 1 == len(node.Arguments)
		pattern = node.Arguments[0]
		condition = expandPattern(matchValue, pattern)
		return [|
			if $condition:
				$(node.Block)
		|]

	def expandPattern(matchValue as Expression, pattern as Expression) as Expression:
		mie = pattern as MethodInvocationExpression
		if mie is not null:
			return expandObjectPattern(matchValue, mie)

		memberRef = pattern as MemberReferenceExpression
		if memberRef is not null:
			return expandValuePattern(matchValue, memberRef)

		reference = pattern as ReferenceExpression
		if reference is not null:
			return expandBindPattern(matchValue, reference)

		quasiquote = pattern as QuasiquoteExpression
		if quasiquote is not null:
			return expandQuasiquotePattern(matchValue, quasiquote)

		capture = pattern as BinaryExpression
		if isCapture(capture):
			return expandCapturePattern(matchValue, capture)

		fixedSize = pattern as ArrayLiteralExpression
		if fixedSize is not null:
			return expandFixedSizePattern(matchValue, fixedSize)

		return expandValuePattern(matchValue, pattern)

	def isCapture(node as BinaryExpression):
		if node is null: return false
		if node.Operator != BinaryOperatorType.Assign: return false
		return node.Left isa ReferenceExpression and node.Right isa MethodInvocationExpression

	def expandBindPattern(matchValue as Expression, node as ReferenceExpression):
		return [| __eval__($node = $matchValue, true) |]

	def expandValuePattern(matchValue as Expression, node as Expression):
		return [| $matchValue == $node |]

	def expandCapturePattern(matchValue as Expression, node as BinaryExpression):
		return expandObjectPattern(matchValue, node.Left, node.Right)

	def expandObjectPattern(matchValue as Expression, node as MethodInvocationExpression) as Expression:

		if len(node.NamedArguments) == 0 and len(node.Arguments) == 0:
			return [| $matchValue isa $(typeRef(node)) |]

		return expandObjectPattern(matchValue, newTemp(node), node)

	def expandObjectPattern(matchValue as Expression, temp as ReferenceExpression, node as MethodInvocationExpression) as Expression:

		condition = [| ($matchValue isa $(typeRef(node))) and __eval__($temp = cast($(typeRef(node)), $matchValue), true) |]
		condition.LexicalInfo = node.LexicalInfo

		for member in node.Arguments:
			assert member isa ReferenceExpression, "Invalid argument '${member}' in pattern '${node}'."
			memberRef = MemberReferenceExpression(member.LexicalInfo, temp.CloneNode(), member.ToString())
			condition = [| $condition and __eval__($member = $memberRef, true) |]

		for member in node.NamedArguments:
			namedArgCondition = expandMemberPattern(temp.CloneNode(), member)
			condition = [| $condition and $namedArgCondition |]

		return condition

	class QuasiquotePatternBuilder(DepthFirstVisitor):

		_expansion as MatchExpansion
		_pattern as Expression

		def constructor(expansion as MatchExpansion):
			_expansion = expansion

		def build(node as QuasiquoteExpression):
			return expand(node.Node)

		def expand(node as Node):
			node.Accept(self)
			expansion = _pattern
			_pattern = null
			assert expansion is not null, "Unsupported pattern '${node}'"
			return expansion

		override def OnSpliceExpression(node as SpliceExpression):
			_pattern = node.Expression

		override def OnUnaryExpression(node as UnaryExpression):
			_pattern = [| UnaryExpression(Operator: UnaryOperatorType.$(node.Operator.ToString()), Operand: $(expand(node.Operand))) |]

		override def OnBinaryExpression(node as BinaryExpression):
			_pattern = [| BinaryExpression(Operator: BinaryOperatorType.$(node.Operator.ToString()), Left: $(expand(node.Left)), Right: $(expand(node.Right))) |]

		override def OnReferenceExpression(node as ReferenceExpression):
			_pattern = [| ReferenceExpression(Name: $(node.Name)) |]

	def objectPatternFor(node as QuasiquoteExpression):
		return QuasiquotePatternBuilder(self).build(node)

	def expandQuasiquotePattern(matchValue as Expression, node as QuasiquoteExpression) as Expression:
		return expandObjectPattern(matchValue, objectPatternFor(node))

	def expandMemberPattern(matchValue as Expression, member as ExpressionPair):
		memberRef = MemberReferenceExpression(member.First.LexicalInfo, matchValue, member.First.ToString())
		return expandPattern(memberRef, member.Second)

	def expandFixedSizePattern(matchValue as Expression, pattern as ArrayLiteralExpression):
		condition = [| $(len(pattern.Items)) == len($matchValue) |]
		i = 0
		for item in pattern.Items:
			itemValue = [| $matchValue[$i] |]
			itemPattern = expandPattern(itemValue, item)
			condition = [| $condition and $itemPattern |]
			++i
		return condition

	def typeRef(node as MethodInvocationExpression):
		return node.Target

	def newTemp(e as Expression):
		return ReferenceExpression(
				LexicalInfo: e.LexicalInfo,
				Name: "$match$${context.AllocIndex()}")


test uint -> long and ulong -> int conversions as well

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

import NUnit.Framework
import BooCompiler.Tests from BooCompiler.Tests

i0 as int = Constants.UnsignedInt
i1 as int = Constants.UnsignedLong
l0 as long = Constants.UnsignedLong
l1 as long = Constants.UnsignedInt

Assert.AreEqual(Constants.UnsignedInt, i0)
Assert.AreEqual(Constants.UnsignedLong, i1)
Assert.AreEqual(Constants.UnsignedLong, l0)
Assert.AreEqual(Constants.UnsignedInt, l1)

import NUnit.Framework
import BooCompiler.Tests from BooCompiler.Tests

i as int = Constants.UnsignedInt
l as long = Constants.UnsignedLong

Assert.AreEqual(Constants.UnsignedInt, i)
Assert.AreEqual(Constants.UnsignedLong, l)


Remove traces of hints-server

Remove traces of hints-server

namespace boojs

from System.IO import Directory, Path
from Boo.Lang.Useful.CommandLine import *

class CommandLine(AbstractCommandLine):

    [getter(Classpaths)]
    _classpaths = List[of string]()

    [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 {filename}", ShortForm: "o", LongForm: "out")]
    public OutputDirectory = "."

    [Option("Select a pipeline (boo or js prints code)", ShortForm: 'p', LongForm: "pipeline")]
    public Pipeline as string

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

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

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

    [Option("Embeds types metadata into the generated file (on by default).", LongForm: "embedtypes")]
    public EmbedTypes = true

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

        _references.AddUnique(Unquote(reference))

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

    [Option("Specify an output {file} where to generate source map (- to embed)", LongForm: "srcmap")]
    public SourceMap as string = null
    [Option("Root {prefix} for source map files", LongForm: "srcmap-root")]
    public SourceMapRoot as string = null

    # TODO: Add option to launch external program on compilation failure
    [Option("Watch files and recompile", ShortForm: "w", LongForm: "watch")]
    public Watch as bool = false

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

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

    def Unquote(path as string):
        if path.StartsWith('"') or path.StartsWith("'"):
            return path[1:-1]
        return path

namespace boojs

from System.IO import Directory, Path
from Boo.Lang.Useful.CommandLine import *

class CommandLine(AbstractCommandLine):

    [getter(Classpaths)]
    _classpaths = List[of string]()

    [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 self.HintsServer or len(self._sourceFiles) > 0 or len(self._srcDirs) > 0

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

    [Option("Select a pipeline (boo or js prints code)", ShortForm: 'p', LongForm: "pipeline")]
    public Pipeline as string

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

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

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

    [Option("Embeds types metadata into the generated file (on by default).", LongForm: "embedtypes")]
    public EmbedTypes = true

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

        _references.AddUnique(Unquote(reference))

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

    [Option("Specify an output {file} where to generate source map (- to embed)", LongForm: "srcmap")]
    public SourceMap as string = null
    [Option("Root {prefix} for source map files", LongForm: "srcmap-root")]
    public SourceMapRoot as string = null

    # TODO: Add option to launch external program on compilation failure
    [Option("Watch files and recompile", ShortForm: "w", LongForm: "watch")]
    public Watch as bool = false

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

    [Option("Launch the compiler in hints mode", LongForm: "hints-server")]
    public HintsServer as bool = false

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

    def Unquote(path as string):
        if path.StartsWith('"') or path.StartsWith("'"):
            return path[1:-1]
        return path


Updating build script again...

Updating build script again...

configuration = "release"
test_assembly = "src/FluentLinqToSql.Tests/bin/${configuration}/FluentLinqToSql.Tests.dll"
dbtest_assembly = "src/FluentLinqToSql.DatabaseTests/bin/${configuration}/FluentLinqToSql.DatabaseTests.dll"
dbtest_enabled = true

target default, (init, compile, test, createDb, dbTest, deploy, package):
  pass

target ci, (init, compile, createDb, coverage, deploy, package):
  pass

target init:
  rmdir("build")

target noDatabase:
  dbtest_enabled = false

target compile:
  msbuild(file: "FluentLinqToSql.sln", configuration: "release")

target test:
  nunit(assembly: test_assembly)

target createDb:
  if not dbtest_enabled:
    print "Skipping database creation"
    return
  print "Trying to create test db"
  nunit(assembly: dbtest_assembly, include: "CreateDatabase")
  print "Test database created"

target dbTest:
  if not dbtest_enabled:
    print "Skipping database tests"
    return
  nunit(assembly: dbtest_assembly)

target deploy:
  with FileList():
    .Include("src/FluentLinqToSql/bin/${configuration}/*.{dll,pdb,xml}")
    .Include("readme.txt")
    .Include("License.txt")
    .Flatten(true)
    .ForEach def(file):
      file.CopyToDirectory("build/${configuration}")

target package:
  zip("build/${configuration}", "build/FluentLinqToSql.zip")

target coverage:
  ncover_path = "c:/program files (x86)/ncover"
  app_assemblies = ("FluentLinqToSql",)
  teamcity_launcher = env("teamcity.dotnet.nunitlauncher")

  #ensure the dbtest assembly is in the right place...
  cp(dbtest_assembly, "src/FluentLinqToSql.Tests/bin/${configuration}/FluentLinqToSql.DatabaseTests.dll")

  with ncover():
    .toolPath = "${ncover_path}/NCover.console.exe"
    .reportDirectory = "build/Coverage"
    .workingDirectory = "src/FluentLinqToSql.Tests/bin/${configuration}"
    .applicationAssemblies = app_assemblies
    .program = "${teamcity_launcher} v2.0 x86 NUnit-2.4.6"
    .testAssembly = "FluentLinqToSql.Tests.dll;FluentLinqToSql.DatabaseTests.dll"
    .excludeAttributes = "System.Runtime.CompilerServices.CompilerGeneratedAttribute"

  with ncover_explorer():
    .toolPath = "${ncover_path}/NCoverExplorer.console.exe"
    .project = "FluentLinqToSql"
    .reportDirectory = "build/coverage"

configuration = "release"
test_assembly = "src/FluentLinqToSql.Tests/bin/${configuration}/FluentLinqToSql.Tests.dll"
dbtest_assembly = "src/FluentLinqToSql.DatabaseTests/bin/${configuration}/FluentLinqToSql.DatabaseTests.dll"
dbtest_enabled = true

target default, (init, compile, test, createDb, dbTest, deploy, package):
  pass

target ci, (init, compile, createDb, coverage, deploy, package):
  pass

target init:
  rmdir("build")

target noDatabase:
  dbtest_enabled = false

target compile:
  msbuild(file: "FluentLinqToSql.sln", configuration: "release")

target test:
  nunit(assembly: test_assembly)

target createDb:
  if not dbtest_enabled:
    print "Skipping database creation"
    return
  print "Trying to create test db"
  nunit(assembly: dbtest_assembly, include: "CreateDatabase")
  print "Test database created"

target dbTest:
  if not dbtest_enabled:
    print "Skipping database tests"
    return
  nunit(assembly: dbtest_assembly)

target deploy:
  with FileList():
    .Include("src/FluentLinqToSql/bin/${configuration}/*.{dll,pdb,xml}")
    .Include("readme.txt")
    .Include("License.txt")
    .Flatten(true)
    .ForEach def(file):
      file.CopyToDirectory("build/${configuration}")

target package:
  zip("build/${configuration}", "build/FluentLinqToSql.zip")

target coverage:
  ncover_path = "c:/program files (x86)/ncover"
  app_assemblies = ("FluentLinqToSql",)
  teamcity_launcher = env("teamcity.dotnet.nunitlauncher")

  #ensure the dbtest assembly is in the right place...
  cp(dbtest_assembly, "src/FluentLinqToSql.Tests/bin/${configuration}/FluentLinqToSql.DatabaseTests.dll")

  with ncover():
    .toolPath = "${ncover_path}/NCover.console.exe"
    .reportDirectory = "build/Coverage"
    .workingDirectory = "src/FluentLinqToSql.Tests/bin/${project_configuration}"
    .applicationAssemblies = app_assemblies
    .program = "${teamcity_launcher} v2.0 x86 NUnit-2.4.6"
    .testAssembly = "FluentLinqToSql.Tests.dll;FluentLinqToSql.DatabaseTests.dll"
    .excludeAttributes = "System.Runtime.CompilerServices.CompilerGeneratedAttribute"

  with ncover_explorer():
    .toolPath = "${ncover_path}/NCoverExplorer.console.exe"
    .project = "FluentLinqToSql"
    .reportDirectory = "build/coverage"