jquery on method

jquery on method

namespace BooJs.Lang.Apis

from BooJs.Lang.Globals import Object
from BooJs.Lang.Builtins import ICallable
from BooJs.Lang.Extensions import ExternAttribute
import BooJs.Lang.Browser.Dom2 as DOM  # TODO: Doesn't work with from ... import ... syntax
from BooJs.Lang.Async import IPromise

[Extern(Factory:true)]
class jQuery(ICallable):

    interface Promise(IPromise):
        def @then(ok as callable, error as callable, progress as callable) as Promise
        def done(cb as callable) as Promise
        def fail(cb as callable) as Promise
        def always(cb as callable) as Promise
        def pipe(okfilter as callable, failfilter as callable, progressfilter as callable) as Promise
        def isResolved() as bool
        def isRejected() as bool

    interface jqXHR(Promise):
        def success(cb as callable) as Promise
        def error(cb as callable) as Promise
        def complete(cb as callable) as Promise

    # Utilities (static)
    static def map(arr as (object), callback as callable) as (object):
        pass
    static def each(obj as Hash, callback as callable) as Hash:
        pass
    static def merge(arr1 as (object), arr2 as (object)) as (object):
        pass
    static def unique(arr as (object)) as (object):
        pass
    static def inArray(hay as object, haystack as (object)) as bool:
        pass
    static def makeArray(obj as object) as (object):
        pass
    static def grep(arr as (object), callback as callable, invert as bool) as (object):
        pass
    static def grep(arr as (object), callback as callable) as (object):
        pass

    static def extend(deep as bool, target as object, obj1 as object) as object:
        pass
    static def extend(target as object, obj1 as object) as object:
        pass
    # Conflicts with instance method
    #static def extend(obj1 as object) as object:
    #    pass
    static def extend(target as object, obj1 as object, obj2 as object) as object:
        pass
    # ...

    static def isArray(val as object) as bool:
        pass
    static def isFunction(val as object) as bool:
        pass

    static def trim(val as string) as string:
        pass

    static def param(elems as (DOM.Element)) as string:
        pass
    static def param(jq as jQuery) as string:
        pass
    static def param(obj as object) as string:
        pass

    static def get(url as string) as jqXHR:
        pass

    static def post(url as string) as jqXHR:
        pass
    static def post(url as string, data as Hash) as jqXHR:
        pass

    static def ajax(url as string) as jqXHR:
        pass
    static def ajax(url as string, settings as Hash) as jqXHR:
        pass
    static def ajax(settings as Hash) as jqXHR:
        pass

    # Instance members

    context as DOM.Element:
        get: pass
    length as uint:
        get: pass
    selector as string:
        get: pass

    # TODO: Use Transform to convert the instance creation into a simple call
    # TODO: Perhaps we should have a specialized attribute to signal constructors/factories that don't use `new` in JS
    def constructor():
        pass
    def constructor(expr_or_html as string):
        pass
    def constructor(expression as string, context as jQuery):
        pass
    def constructor(html as string, document as DOM.Document):
        pass
    def constructor(element as DOM.Element):
        pass
    def constructor(elements as (DOM.Element)):
        pass
    # TODO: Why doesn't the compiler tell apart callables from objects?
    # def constructor(callback as callable):
    #     pass
    def constructor(any as object):
        pass

    # Callable interface
    def Call(args as (Object)) as Object:
        pass
    # callable methods for BooJs
    def Call(expr_or_html as string) as jQuery:
        pass
    def Call(expression as string, context as jQuery) as jQuery:
        pass
    def Call(html as string, document as DOM.Document) as jQuery:
        pass
    def Call(element as DOM.Element) as jQuery:
        pass
    def Call(elements as (DOM.Element)) as jQuery:
        pass
    def Call(callback as callable) as jQuery:
        pass

    # Core - Accessors
    def index(subject as jQuery) as int:
        pass
    def index(subject as DOM.Element) as int:
        pass

    #def each(callback as callable(object)) as jQuery:
    #    pass
    def each(callback as callable) as jQuery:
        pass

    def size() as uint:
        pass

    def get() as (DOM.Element):
        pass
    def get(index as int) as DOM.Element:
        pass

    def eq(position as int) as jQuery:
        pass

    # Core - Data
    def queue(name as string, callback as callable) as jQuery:
        pass
    def queue(callback as callable) as jQuery:
        pass
    def queue(name as string) as (callable):
        pass
    def queue(name as string, queue as (callable)) as jQuery:
        pass
    def dequeue(name as string) as jQuery:
        pass
    def dequeue() as jQuery:
        pass

    def data(name as string) as object:
        pass
    def data(name as string, value as object) as jQuery:
        pass
    def removeData(name as string) as jQuery:
        pass

    # Core - Plugins
    def extend(obj as object) as jQuery:
        pass
    # TODO: $.fn.extend ??

    # Core - Interoperability
    def noConflict() as jQuery:
        pass
    def noConflict(extreme as bool) as jQuery:
        pass

    # Attributes
    def attr(name as string) as string:
        pass
    def attr(props as Hash) as jQuery:
        pass
    def attr(key as string, value as string) as jQuery:
        pass
    def attr(key as string, resolver as callable) as jQuery:
        pass
    def removeAttr(name as string) as jQuery:
        pass

    def toggleClass(cls as string, switch as bool) as jQuery:
        pass
    def toggleClass(cls as string) as jQuery:
        pass
    def addClass(cls as string) as jQuery:
        pass
    def hasClass(cls as string) as bool:
        pass
    def removeClass(cls as string) as jQuery:
        pass

    def html() as string:
        pass
    def html(val as string) as jQuery:
        pass

    def text() as string:
        pass
    def text(val as string) as jQuery:
        pass

    def val() as string: # or (string)
        pass
    def val(val as string) as jQuery:
        pass
    def val(vals as (string)) as jQuery:
        pass

    # Traversing - Filtering
    #def is(expression as string) as bool
    def filter(expr as string) as jQuery:
        pass
    def filter(resolver as callable) as jQuery:
        pass
    #def not(expr as string) as jQuery
    def slice(start as int) as jQuery:
        pass
    def slice(start as int, stop as int) as jQuery:
        pass
    def map(callback as callable) as jQuery:
        pass

    # Traversing - Finding
    def parent(expr as string) as jQuery:
        pass
    def parent() as jQuery:
        pass

    def parents(expr as string) as jQuery:
        pass
    def parents() as jQuery:
        pass

    def find(expr as string) as jQuery:
        pass

    def prev(expr as string) as jQuery:
        pass
    def prev() as jQuery:
        pass
    def prevAll(expr as string) as jQuery:
        pass
    def prevAll() as jQuery:
        pass

    def next(expr as string) as jQuery:
        pass
    def next() as jQuery:
        pass
    def nextAll(expr as string) as jQuery:
        pass
    def nextAll() as jQuery:
        pass

    def siblings(expr as string) as jQuery:
        pass
    def siblings() as jQuery:
        pass

    def add(expr as string) as jQuery:
        pass
    def add(expr as DOM.Element) as jQuery:
        pass
    def add(expr as (DOM.Element)) as jQuery:
        pass

    def children(expr as string) as jQuery:
        pass
    def children() as jQuery:
        pass

    def closests(expr as string) as jQuery:
        pass

    def contents() as jQuery:
        pass

    def offsetParent() as jQuery:
        pass

    # Traversing - chaining
    def andSelf() as jQuery:
        pass
    def end() as jQuery:
        pass

    # Manipulation
    def append(content as string) as jQuery:
        pass
    def append(content as DOM.Element) as jQuery:
        pass
    def append(content as jQuery) as jQuery:
        pass
    def appendTo(selector as string) as jQuery:
        pass

    def prepend(content as string) as jQuery:
        pass
    def prepend(content as DOM.Element) as jQuery:
        pass
    def prepend(content as jQuery) as jQuery:
        pass
    def prependTo(selector as string) as jQuery:
        pass

    # .......

    def fadeIn() as jQuery:
        pass
    def fadeIn(duration as int) as jQuery:
        pass
    def fadeIn(duration as int, callback as callable) as jQuery:
        pass
    def fadeIn(duration as int, easing as string) as jQuery:
        pass
    def fadeIn(duration as int, easing as string, callback as callable) as jQuery:
        pass

    def fadeOut() as jQuery:
        pass
    def fadeOut(duration as int) as jQuery:
        pass
    def fadeOut(duration as int, callback as callable) as jQuery:
        pass
    def fadeOut(duration as int, easing as string) as jQuery:
        pass
    def fadeOut(duration as int, easing as string, callback as callable) as jQuery:
        pass

    def promise() as Promise:
        pass
    def promise(type as string) as Promise:
        pass
    def promise(type as string, target as object) as Promise:
        pass

    def on(evt as string, fn as callable) as jQuery:
        pass


change the working directory before executing the script

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

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

namespace Boo.NAnt

import System
import System.Diagnostics
import System.IO
import NAnt.Core
import NAnt.Core.Attributes
import NAnt.Core.Types
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Pipelines
import Boo.Lang.Compiler.Steps

class AbstractScript:

	[property(Project)]
	_project as Project

	[property(Task)]
	_task as BooTask

	def print(msg):
		_task.LogInfo(msg)

	abstract def Run():
		pass

class PrepareScriptStep(AbstractCompilerStep):

	override def Run():
		module = CompileUnit.Modules[0]

		method = Method(Name: "Run",
						Modifiers: TypeMemberModifiers.Override,
						Body: module.Globals)

		module.Globals = Block()

		script = ClassDefinition(Name: "__Script__")
		script.BaseTypes.Add(SimpleTypeReference("Boo.NAnt.AbstractScript"))
		script.Members.Add(method)
		script.Members.Extend(module.Members)

		module.Members.Clear()
		module.Members.Add(script)

class WithWorkingDir(IDisposable):
	_saved as string
	def constructor(dir as string):
		_saved = Environment.CurrentDirectory
		Environment.CurrentDirectory = dir
	def Dispose():
		Environment.CurrentDirectory = _saved

[TaskName("boo")]
class BooTask(AbstractBooTask):

	_src as FileInfo

	[TaskAttribute("src", Required: false)]
	Source:
		get:
			return _src
		set:
			_src = value

	override def ExecuteTask():

		compiler = BooCompiler()
		parameters = compiler.Parameters
		parameters.OutputType = CompilerOutputType.Library
		if _src:
			parameters.Input.Add(FileInput(_src.ToString()))
		else:
			parameters.Input.Add(StringInput("boo", reindent(getSourceCode())))
		parameters.References.Add(GetType().Assembly)
		parameters.References.Add(typeof(NAnt.Core.Project).Assembly)

		result = RunCompiler(compiler)

		print("script successfully compiled.")
		using WithWorkingDir(Project.BaseDirectory):
			try:
				scriptType = result.GeneratedAssembly.GetType("__Script__", true)
				script as AbstractScript = scriptType()
				script.Project = Project
				script.Task = self
				script.Run()
			except x:
				raise BuildException(x.Message, Location, x)

	override def GetDefaultPipeline():
		pipeline = CompileToMemory()
		pipeline.Insert(1, PrepareScriptStep())
		return pipeline

	private def getSourceCode():
		codeNode = self.XmlNode.SelectSingleNode("code")
		return (codeNode or self.XmlNode).InnerText

	private def reindent(code as string):
		lines = /\n/.Split(code.Replace("\r\n", "\n"))
		lines = [line for line in lines if len(line.Trim())].ToArray(string)

		first = lines[0]
		indent = /(\s*)/.Match(first).Groups[0].Value
		return code if 0 == len(indent)

		buffer = System.Text.StringBuilder()
		for line in lines:
			if not line.StartsWith(indent):
				return code // let the parser complain about it
			else:
				buffer.Append(line[len(indent):])
				buffer.Append("\n")
		return buffer.ToString()

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

namespace Boo.NAnt

import System.Diagnostics
import System.IO
import NAnt.Core
import NAnt.Core.Attributes
import NAnt.Core.Types
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Pipelines
import Boo.Lang.Compiler.Steps

class AbstractScript:

	[property(Project)]
	_project as Project

	[property(Task)]
	_task as BooTask

	def print(msg):
		_task.LogInfo(msg)

	abstract def Run():
		pass

class PrepareScriptStep(AbstractCompilerStep):

	override def Run():
		module = CompileUnit.Modules[0]

		method = Method(Name: "Run",
						Modifiers: TypeMemberModifiers.Override,
						Body: module.Globals)

		module.Globals = Block()

		script = ClassDefinition(Name: "__Script__")
		script.BaseTypes.Add(SimpleTypeReference("Boo.NAnt.AbstractScript"))
		script.Members.Add(method)
		script.Members.Extend(module.Members)

		module.Members.Clear()
		module.Members.Add(script)

[TaskName("boo")]
class BooTask(AbstractBooTask):

	_src as FileInfo

	[TaskAttribute("src", Required: false)]
	Source:
		get:
			return _src
		set:
			_src = value

	override def ExecuteTask():

		compiler = BooCompiler()
		parameters = compiler.Parameters
		parameters.OutputType = CompilerOutputType.Library
		if _src:
			parameters.Input.Add(FileInput(_src.ToString()))
		else:
			parameters.Input.Add(StringInput("boo", reindent(getSourceCode())))
		parameters.References.Add(GetType().Assembly)
		parameters.References.Add(typeof(NAnt.Core.Project).Assembly)

		result = RunCompiler(compiler)

		print("script successfully compiled.")

		try:
			scriptType = result.GeneratedAssembly.GetType("__Script__", true)
			script as AbstractScript = scriptType()
			script.Project = Project
			script.Task = self
			script.Run()
		except x:
			raise BuildException(x.Message, Location, x)

	override def GetDefaultPipeline():
		pipeline = CompileToMemory()
		pipeline.Insert(1, PrepareScriptStep())
		return pipeline

	private def getSourceCode():
		codeNode = self.XmlNode.SelectSingleNode("code")
		return (codeNode or self.XmlNode).InnerText

	private def reindent(code as string):
		lines = /\n/.Split(code.Replace("\r\n", "\n"))
		lines = [line for line in lines if len(line.Trim())].ToArray(string)

		first = lines[0]
		indent = /(\s*)/.Match(first).Groups[0].Value
		return code if 0 == len(indent)

		buffer = System.Text.StringBuilder()
		for line in lines:
			if not line.StartsWith(indent):
				return code // let the parser complain about it
			else:
				buffer.Append(line[len(indent):])
				buffer.Append("\n")
		return buffer.ToString()


a few more benchmarks to get a feel of the progress

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

import Boo.Lang.Runtime

def benchmark(label, method as callable()):
	start = date.Now
	for i in range(5000000):
		method()
	print "${label}\t", (date.Now-start).TotalSeconds

class Item:
	[property(Name)]
	public name = ""

class ListExtensions:
	[extension]
	static def addX(l as List, value):
		l.Add(value)

	[extension]
	static length[l as List]:
		get:
			return l.Count

benchmark "int*int":
	a as duck = 3
	b as duck = 2
	c = a*b

benchmark "static int*int":
	a = 3
	b = 2
	c = a*b

benchmark "List*int":
	a as duck = [1, 2, 3]
	b as duck = 2
	c = a*b

benchmark "static List*int":
	a = [1, 2, 3]
	b = 2
	c = a*b

benchmark "List.Add":
	b as duck = [1, 2, 3]
	b.Add(4)

RuntimeServices.WithExtensions(ListExtensions):
	benchmark "extension List.Add":
		b as duck = [1, 2, 3]
		b.addX(4)

benchmark "static List.Add":
	b = [1, 2, 3]
	b.Add(4)

benchmark "property":
	b as duck = []
	c = b.Count

RuntimeServices.WithExtensions(ListExtensions):
	benchmark "extension property":
		b as duck = []
		c = b.length

benchmark "static property":
	b = []
	c = b.Count

benchmark "indexer":
	b as duck = [1]
	c = b[0]

benchmark "static indexer":
	b = [1]
	c = b[0]

benchmark "set field":
	(Item() as duck).name = "foo"

benchmark "static set field":
	Item().name = "foo"

benchmark "set property":
	(Item() as duck).name = "foo"

benchmark "static set property":
	Item().name = "foo"

import Boo.Lang.Runtime

def benchmark(label, method as callable()):
	start = date.Now
	for i in range(5000000):
		method()
	print "${label}\t", (date.Now-start).TotalSeconds

class ListExtensions:
	[extension]
	static def addX(l as List, value):
		l.Add(value)

	[extension]
	static length[l as List]:
		get:
			return l.Count

benchmark "int*int":
	a as duck = 3
	b as duck = 2
	c = a*b

benchmark "static int*int":
	a = 3
	b = 2
	c = a*b

benchmark "List*int":
	a as duck = [1, 2, 3]
	b as duck = 2
	c = a*b

benchmark "static List*int":
	a = [1, 2, 3]
	b = 2
	c = a*b

benchmark "List.Add":
	b as duck = [1, 2, 3]
	b.Add(4)

RuntimeServices.WithExtensions(ListExtensions):
	benchmark "extension List.Add":
		b as duck = [1, 2, 3]
		b.addX(4)

benchmark "static List.Add":
	b = [1, 2, 3]
	b.Add(4)

benchmark "property":
	b as duck = []
	c = b.Count

RuntimeServices.WithExtensions(ListExtensions):
	benchmark "extension property":
		b as duck = []
		c = b.length

benchmark "static property":
	b = []
	c = b.Count


distro-version was renamed to boo.version

git-svn-id: c3b8989232654601f1acea7403f771adaaa44a81@1551 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

import System

version = Project.Properties["boo.version"]

trunk = getTrunkUri()
tag = Uri(trunk, "tags/${version}")

print(svn("cp ${trunk} ${tag} -m '${version} release'"))

#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

import System

version = Project.Properties["distro-version"]

trunk = getTrunkUri()
tag = Uri(trunk, "tags/${version}")

print(svn("cp ${trunk} ${tag} -m '${version} release'"))


procura os icones no path do exe

procura os icones no path do exe

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

namespace BooExplorer

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

class DocumentOutline(Content):

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

	def constructor():
		InitImageList()
		InitTreeView()

		_treeViewVisitor = TreeViewVisitor(_tree)

		SuspendLayout()

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

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

	def InitImageList():
		_imageList = ImageList()
		appPath = Path.GetDirectoryName(Application.ExecutablePath)

		try:
			_imageList.Images.Add(Image.FromFile(Path.Combine(appPath, "namespace.png")))
			_imageList.Images.Add(Image.FromFile(Path.Combine(appPath, "class.png")))
			_imageList.Images.Add(Image.FromFile(Path.Combine(appPath, "interface.png")))
			_imageList.Images.Add(Image.FromFile(Path.Combine(appPath, "field.png")))
			_imageList.Images.Add(Image.FromFile(Path.Combine(appPath, "property.png")))
			_imageList.Images.Add(Image.FromFile(Path.Combine(appPath, "enum.png")))
			_imageList.Images.Add(Image.FromFile(Path.Combine(appPath, "method.png")))
		except ex as FileNotFoundException:
			pass

	def InitTreeView():
		_tree = TreeView(Dock: DockStyle.Fill,
						DoubleClick: _tree_DoubleClick,
						ImageIndex: 0,
						SelectedImageIndex: 0,
						ImageList: _imageList)

	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.Switch(_module)

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

	def _tree_DoubleClick(sender, args as EventArgs):
		return unless _activeDocument

		if (treeNode = _tree.SelectedNode):
			node as Node = treeNode.Tag
			if node is not null:
				info = node.LexicalInfo
				_activeDocument.GoTo(info.Line-1)

class TreeViewVisitor(DepthFirstSwitcher):

	_tree as TreeView
	_current as TreeNode

	def constructor(tree):
		_tree = tree

	override def OnModule(node as Module):

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

		_tree.BeginUpdate()
		_tree.Nodes.Clear()
		if len(_current.Nodes):
			_tree.Nodes.AddRange(array(TreeNode, _current.Nodes))
			_tree.ExpandAll()
			_tree.Nodes[0].EnsureVisible()
		_tree.EndUpdate()

	override def OnProperty(node as Property):
		Add(node.Name, 4, 4, node)

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

	override def OnInterfaceDefinition(node as InterfaceDefinition):
		OnTypeDefinition(node, 2, 2)

	override def OnClassDefinition(node as ClassDefinition):
		OnTypeDefinition(node, 1, 1)

	override def OnEnumDefinition(node as EnumDefinition):
		OnTypeDefinition(node, 5, 5)

	def OnTypeDefinition(node as TypeDefinition, imageIndex, selectedImageIndex):
		saved = _current

		_current = Add(node.Name, imageIndex, selectedImageIndex, node)
		Switch(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, 6, 6, node)

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

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

namespace BooExplorer

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

class DocumentOutline(Content):

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

	def constructor():
		InitImageList()
		InitTreeView()

		_treeViewVisitor = TreeViewVisitor(_tree)

		SuspendLayout()

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

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

	def InitImageList():
		_imageList = ImageList()
		try:
			_imageList.Images.Add(Image.FromFile("namespace.png"))
			_imageList.Images.Add(Image.FromFile("class.png"))
			_imageList.Images.Add(Image.FromFile("interface.png"))
			_imageList.Images.Add(Image.FromFile("field.png"))
			_imageList.Images.Add(Image.FromFile("property.png"))
			_imageList.Images.Add(Image.FromFile("enum.png"))
			_imageList.Images.Add(Image.FromFile("method.png"))
		except ex as FileNotFoundException:
			pass

	def InitTreeView():
		_tree = TreeView(Dock: DockStyle.Fill,
						DoubleClick: _tree_DoubleClick,
						ImageIndex: 0,
						SelectedImageIndex: 0,
						ImageList: _imageList)

	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.Switch(_module)

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

	def _tree_DoubleClick(sender, args as EventArgs):
		return unless _activeDocument

		if (treeNode = _tree.SelectedNode):
			node as Node = treeNode.Tag
			if node is not null:
				info = node.LexicalInfo
				_activeDocument.GoTo(info.Line-1)

class TreeViewVisitor(DepthFirstSwitcher):

	_tree as TreeView
	_current as TreeNode

	def constructor(tree):
		_tree = tree

	override def OnModule(node as Module):

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

		_tree.BeginUpdate()
		_tree.Nodes.Clear()
		if len(_current.Nodes):
			_tree.Nodes.AddRange(array(TreeNode, _current.Nodes))
			_tree.ExpandAll()
			_tree.Nodes[0].EnsureVisible()
		_tree.EndUpdate()

	override def OnProperty(node as Property):
		Add(node.Name, 4, 4, node)

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

	override def OnInterfaceDefinition(node as InterfaceDefinition):
		OnTypeDefinition(node, 2, 2)

	override def OnClassDefinition(node as ClassDefinition):
		OnTypeDefinition(node, 1, 1)

	override def OnEnumDefinition(node as EnumDefinition):
		OnTypeDefinition(node, 5, 5)

	def OnTypeDefinition(node as TypeDefinition, imageIndex, selectedImageIndex):
		saved = _current

		_current = Add(node.Name, imageIndex, selectedImageIndex, node)
		Switch(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, 6, 6, node)

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

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


Fix for WSABooParserTestFixture.as_1 and other 9 tests.

namespace Boo.OMeta.Parser

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

ometa WSABooParser < BooParser:
	scanner = (empty_lines ^ makeToken("eol")) | ((--whitespace, tokens >> t) ^ t)

	keywords = "end" | super

	begin_block = COLON, eol
	end_block = keyword["end"], eol
	empty_block = (begin_block, end_block) ^ Block()

namespace Boo.OMeta.Parser

import Boo.OMeta

ometa WSABooParser < BooParser:
	scanner = (empty_lines ^ makeToken("eol")) | ((--whitespace, tokens >> t) ^ t)

	keywords = "end" | super

	begin_block = COLON, eol
	end_block = keyword["end"], eol


ability to ignore and categorize test cases

"""
Finds all test cases under tests/integration and generates runTestCase calls
in IntegrationTest.Generated.boo

First line of test case can specify a nunit attribute to go with it:
	* "// ignore reason" for [Ignore("reason")]
	* "// category name" for [Category("name")]
"""
import System.IO
import Boo.Lang.PatternMatching

def testCaseName(fname as string):
	return Path.GetFileNameWithoutExtension(fname).Replace("-", "_")

def writeTestCases(writer as TextWriter, baseDir as string):
	count = 0
	for fname in Directory.GetFiles(baseDir):
		continue unless fname.EndsWith(".boo")
		++count
		writeTestCase(writer, fname)
	for subDir in Directory.GetDirectories(baseDir):
		writeTestCases(writer, subDir)
	print("${count} test cases found in ${baseDir}.")

def writeTestCase(writer as TextWriter, fname as string):
	writer.Write("""
	${CategoryAttributeFor(fname)}
	[Test] def ${testCaseName(fname)}():
		runTestCase("${fname.Replace('\\', '/')}")
		""")

def CategoryAttributeFor(testFile as string):
"""
If the first line of the test case file starts with // category CategoryName
then return a suitable [CategoryName()] attribute.
"""
	match FirstLineOf(testFile):
		case /\/\/\s*ignore\s+(?<reason>.*)/:
			return "[Ignore(\"${reason[0].Value.Trim()}\")]"
		case /\/\/\s*category\s+(?<name>.*)/:
			return "[Category(\"${name[0].Value.Trim()}\")]"
		otherwise:
			return ""

def FirstLineOf(fname as string):
	using reader=File.OpenText(fname):
		return reader.ReadLine()

using writer = StreamWriter("src/Boojay.Compilation.Tests/IntegrationTest.Generated.boo"):
	writer.Write("""
namespace Boojay.Compilation.Tests

import NUnit.Framework

partial class IntegrationTest:
""")

	writeTestCases(writer, "tests/integration")

"""
Finds all test cases under tests/integration and generates runTestCase calls
in IntegrationTest.Generated.boo
"""
import System.IO

def testCaseName(fname as string):
	return Path.GetFileNameWithoutExtension(fname).Replace("-", "_")

def writeTestCases(writer as TextWriter, baseDir as string):
	count = 0
	for fname in Directory.GetFiles(baseDir):
		continue unless fname.EndsWith(".boo")
		++count
		writeTestCase(writer, fname)
	for subDir in Directory.GetDirectories(baseDir):
		writeTestCases(writer, subDir)
	print("${count} test cases found in ${baseDir}.")

def writeTestCase(writer as TextWriter, fname as string):
	writer.Write("""
	[Test]
	def ${testCaseName(fname)}():
		runTestCase("${fname.Replace('\\', '/')}")
		""")

using writer = StreamWriter("src/Boojay.Compilation.Tests/IntegrationTest.Generated.boo"):
	writer.Write("""
namespace Boojay.Compilation.Tests

import NUnit.Framework

partial class IntegrationTest:
""")

	writeTestCases(writer, "tests/integration")


booi will try to find the assemblies in the current folder first

git-svn-id: c3b8989232654601f1acea7403f771adaaa44a81@339 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

import System
import System.IO
import System.Reflection
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO

class AssemblyResolver:

	_cache = {}

	def AssemblyResolve(sender, args as ResolveEventArgs) as Assembly:
		parts = /,\s*/.Split(args.Name)
		simpleName = parts[0]

		asm as Assembly = _cache[simpleName]
		if asm is null:
			basePath = Path.GetFullPath(simpleName)
			asm = probeFile(basePath + ".dll")
			if asm is null:
				asm = probeFile(basePath + ".exe")
			_cache[simpleName] = asm

		return asm

def main(argv as (string)):
	compiler = BooCompiler()
	if "-" == argv[0]:
		compiler.Parameters.Input.Add(ReaderInput("<stdin>", System.Console.In))
	else:
		compiler.Parameters.Input.Add(FileInput(argv[0]))

	// boo memory pipeline
	// compiles the code in memory only
	compiler.Parameters.Pipeline.Load("boom")

	AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolver().AssemblyResolve
	result = compiler.Run()
	if len(result.Errors):
		for error as CompilerError in result.Errors:
			print(error.ToString(true))
	else:
		try:
			result.GeneratedAssemblyEntryPoint.Invoke(null, (argv[1:],))
		except x as TargetInvocationException:
			print(x.InnerException)

def probeFile(fname as string):
	if File.Exists(fname):
		return Assembly.LoadFrom(fname)

if len(argv) > 0:
	main(argv)
else:
	print("booi <script.boo>")

#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

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

def run(argv as (string)):
	compiler = BooCompiler()
	if "-" == argv[0]:
		compiler.Parameters.Input.Add(ReaderInput("<stdin>", System.Console.In))
	else:
		compiler.Parameters.Input.Add(FileInput(argv[0]))

	// boo memory pipeline
	// compiles the code in memory only
	compiler.Parameters.Pipeline.Load("boom")

	result = compiler.Run()
	if len(result.Errors):
		for error as CompilerError in result.Errors:
			print(error.ToString(true))
	else:
		result.GeneratedAssemblyEntryPoint.Invoke(null, (argv[1:],))

if len(argv) > 0:
	run(argv)
else:
	print("booi <script.boo>")


initial support for classes and fields

initial support for classes and fields

namespace Boojay.Compilation

import System.IO

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

import Boo.PatternMatching

import org.objectweb.asm
import org.objectweb.asm.Type

class BoojayEmitter(AbstractVisitorCompilerStep):

	_classWriter as ClassWriter
	_code as MethodVisitor
	_typeMappings as Hash
	_primitiveMappings as Hash

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

	def Run():
		Visit(CompileUnit)

	def initializeTypeMappings():
		_typeMappings = {
			typeSystem.ObjectType: "java/lang/Object",
			typeSystem.StringType: "java/lang/String",
		}

		_primitiveMappings = {
			typeSystem.BoolType: BOOLEAN_TYPE.getDescriptor(),
			typeSystem.IntType: INT_TYPE.getDescriptor(),
			typeSystem.VoidType: VOID_TYPE.getDescriptor(),
		}

	override def EnterClassDefinition(node as ClassDefinition):
		_classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS)
		_classWriter.visit(
			Opcodes.V1_5,
			Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
			node.FullName,
			null,
			typeDescriptor(baseType(node)),
			null)
		return true

	override def LeaveClassDefinition(node as ClassDefinition):
		_classWriter.visitEnd()

		fname = classFullFileName(node)
		ensurePath(fname)
		File.WriteAllBytes(fname, _classWriter.toByteArray())

	override def OnIfStatement(node as IfStatement):

		elseLabel = Label()
		afterElseLabel = Label()

		emitBranchFalse node.Condition, elseLabel
		emit node.TrueBlock
		if node.FalseBlock is not null:
			GOTO afterElseLabel
		mark elseLabel
		if node.FalseBlock is not null:
			emit node.FalseBlock
			mark afterElseLabel

	def emitBranchFalse(e as Expression, label as Label):
		match e:
			case UnaryExpression(
					Operator: UnaryOperatorType.LogicalNot,
					Operand: condition):
				emitBranchTrue condition, label
			otherwise:
				emit e
				IFEQ label

	def emitBranchTrue(e as Expression, label as Label):
		match e:
			case UnaryExpression(
					Operator: UnaryOperatorType.LogicalNot,
					Operand: condition):
				emitBranchFalse condition, label
			otherwise:
				emit e
				IFNE label

	override def OnWhileStatement(node as WhileStatement):

		testLabel = Label()
		bodyLabel = Label()
		GOTO testLabel
		mark bodyLabel
		emit node.Block
		mark testLabel
		emitBranchTrue node.Condition, bodyLabel

	override def OnField(node as Field):
		field = _classWriter.visitField(
					memberAttributes(node),
					node.Name,
					typeDescriptor(entity(node.Type)),
					null,
					null)
		field.visitEnd()

	override def OnConstructor(node as Constructor):
		emitMethod "<init>", node

	override def OnMethod(node as Method):
		methodName = ("main" if node.Name == "Main" else node.Name)
		emitMethod methodName, node

	def emitMethod(methodName as string, node as Method):
		_code = _classWriter.visitMethod(
					memberAttributes(node),
					methodName,
					javaSignature(node),
					null,
					null)

		prepareLocalVariables node

		_code.visitCode()

		emit node.Body
		RETURN

		_code.visitMaxs(0, 0)
		_code.visitEnd()

	def memberAttributes(node as TypeMember):
		attributes = Opcodes.ACC_PUBLIC
		if node.IsStatic: attributes += Opcodes.ACC_STATIC
		return attributes

	def prepareLocalVariables(node as Method):
		i = firstLocalIndex(node)
		for local in node.Locals:
			index(local, i)
			++i

	def firstLocalIndex(node as Method):
		if 0 == len(node.Parameters):
			if node.IsStatic: return 0
			return 1
		return lastParameterIndex(node) + 1

	def lastParameterIndex(node as Method):
		param as InternalParameter = entity(node.Parameters[-1])
		return param.Index

	def index(node as Local, index as int):
		node["index"] = index

	def index(entity as InternalLocal) as int:
		return entity.Local["index"]

	override def LeaveExpressionStatement(node as ExpressionStatement):
		discardValueOnStack node.Expression

	def discardValueOnStack(node as Expression):
		mie = node as MethodInvocationExpression
		if mie is null: return

		m = entity(mie.Target) as IMethod
		if m is null: return

		if hasReturnValue(m): POP

	def hasReturnValue(m as IMethod):
		return m.ReturnType is not TypeSystemServices.VoidType

	override def OnReturnStatement(node as ReturnStatement):
		if node.Expression is null:
			RETURN
		else:
			emit node.Expression
			ARETURN

	override def OnMethodInvocationExpression(node as MethodInvocationExpression):

		match entity(node.Target):
			case ctor = IConstructor():
				match node.Target:
					case SuperLiteralExpression():
						ALOAD 0
						INVOKESPECIAL ctor
					otherwise:
						emitObjectCreation ctor, node
			case method = IMethod():
				emitMethodInvocation method, node
			case builtin = BuiltinFunction():
				emitBuiltinInvocation builtin, node

	def emitBuiltinInvocation(builtin as BuiltinFunction, node as MethodInvocationExpression):
		match builtin.FunctionType:
			case BuiltinFunctionType.Eval:
				emitEval node

	def emitEval(node as MethodInvocationExpression):
		for e in node.Arguments.ToArray()[:-1]:
			emit e
			discardValueOnStack e
		emit node.Arguments[-1]

	def emitMethodInvocation(method as IMethod, node as MethodInvocationExpression):

		if isSpecialIkvmGetter(method):
			emitSpecialIkvmGetter(method)
			return

		emit node.Target
		emit node.Arguments

		if method.IsStatic:
			INVOKESTATIC method
		else:
			INVOKEVIRTUAL method

	def emitObjectCreation(ctor as IConstructor, node as MethodInvocationExpression):
		NEW ctor.DeclaringType
		DUP
		emit node.Arguments
		INVOKESPECIAL ctor

	def emitSpecialIkvmGetter(method as IMethod):
	"""
	in the ikvm version of GNU.ClassPath the
	console streams are mapped to properties
	where in java they should be treated as static fields
	"""
		emitLoadStaticField(
			method.DeclaringType,
			stripGetterPrefix(method.Name),
			method.ReturnType)

	def isSpecialIkvmGetter(method as IMethod):
		return (method.IsStatic
			and method.DeclaringType.FullName == "java.lang.System"
			and method.Name in ("get_out", "get_in", "get_err"))

	override def OnBinaryExpression(node as BinaryExpression):
		match node.Operator:
			case BinaryOperatorType.Assign:
				emitAssignment node
			case BinaryOperatorType.Subtraction:
				emitSubtraction node
			case BinaryOperatorType.Addition:
				emitAddition node

	def emitAddition(node as BinaryExpression):
		emit node.Left
		emit node.Right
		IADD

	def emitSubtraction(node as BinaryExpression):
		emit node.Left
		emit node.Right
		ISUB

	def emitAssignment(node as BinaryExpression):
		match node.Left:
			case memberRef = MemberReferenceExpression():
				match entity(memberRef):
                    case field = IField(IsStatic: false):
                    	emit memberRef.Target
                    	emit node.Right
                    	PUTFIELD field
			case reference = ReferenceExpression():
				emit node.Right
				match entity(reference):
					case local = ILocalEntity():
						if not local.Type.IsValueType:
							ASTORE index(local)
						elif isIntegerOrBool(local.Type):
							ISTORE index(local)

	override def OnMemberReferenceExpression(node as MemberReferenceExpression):
		match entity(node):
			case field = IField(IsStatic: true):
				GETSTATIC field
			case field = IField(IsStatic: false):
				emit node.Target
				GETFIELD field
			case IMethod(IsStatic: false):
				emit node.Target
			case IMethod(IsStatic: true):
				pass

	override def OnReferenceExpression(node as ReferenceExpression):
		match entity(node):
			case param = InternalParameter():
				emitLoad param.Type, param.Index
			case local = ILocalEntity():
				emitLoad local.Type, index(local)

	def emitLoad(type as IType, index as int):
		if not type.IsValueType:
			ALOAD index
		elif isIntegerOrBool(type):
			ILOAD index
		else:
			raise "Unsupported type: ${type}"

	def isIntegerOrBool(type as IType):
		return self.TypeSystemServices.IsIntegerOrBool(type)

	def stripGetterPrefix(name as string):
		return name[len("get_"):]

	override def OnStringLiteralExpression(node as StringLiteralExpression):
		LDC node.Value

	override def OnIntegerLiteralExpression(node as IntegerLiteralExpression):
		ICONST node.Value

	override def OnBoolLiteralExpression(node as BoolLiteralExpression):
		if node.Value:
			ICONST_1
		else:
			ICONST_0

	def baseType(node as ClassDefinition):
		return self.GetType(node).BaseType

	typeSystem as JavaTypeSystem:
		get: return self.TypeSystemServices

	def javaSignature(method as IMethod):
		return ("("
			+ join(typeDescriptor(p.Type) for p in method.GetParameters(), "")
			+ ")"
			+ typeDescriptor(method.ReturnType))

	def javaSignature(node as Method):
		return javaSignature(entity(node) as IMethod)

	def ensurePath(fname as string):
		path = Path.GetDirectoryName(fname)
		if not string.IsNullOrEmpty(path):
			Directory.CreateDirectory(path)

	def classFullFileName(node as TypeDefinition):
		return javaType(entity(node)) + ".class"

	def emit(node as Node):
		Visit(node)

	def emit(nodes as System.Collections.IEnumerable):
		VisitCollection(nodes)

	def LDC(value):
		emitLdcInsn(value)

	def IFEQ(label as Label):
		emitJumpInsn(Opcodes.IFEQ, label)

	def IFNE(label as Label):
        emitJumpInsn(Opcodes.IFNE, label)

	def GOTO(label as Label):
		emitJumpInsn(Opcodes.GOTO, label)

	def ILOAD(index as int):
		emitVarInsn(Opcodes.ILOAD, index)

	def ICONST(value as int):
		if value >= -1 and value <= 5:
			emitInsn(iconstOpcodeFor(value))
		elif value >= -127 and value <= 127:
			emitIntInsn Opcodes.BIPUSH, value
		else:
			emitIntInsn Opcodes.SIPUSH, value

	def ICONST_0():
		emitInsn(Opcodes.ICONST_0)

	def ICONST_1():
		emitInsn(Opcodes.ICONST_1)

	def iconstOpcodeFor(value as int):
		if value == 0: return Opcodes.ICONST_0
		if value == 1: return Opcodes.ICONST_1
		if value == 2: return Opcodes.ICONST_2
		if value == -1: return Opcodes.ICONST_M1
		raise System.ArgumentException("value")

	def ISTORE(index as int):
		emitVarInsn(Opcodes.ISTORE, index)

	def ALOAD(index as int):
		emitVarInsn(Opcodes.ALOAD, index)

	def ASTORE(index as int):
		emitVarInsn(Opcodes.ASTORE, index)

	def GETSTATIC(field as IField):
		emitLoadStaticField(field.DeclaringType, field.Name, field.Type)

	def GETFIELD(field as IField):
		emitField Opcodes.GETFIELD, field

	def PUTFIELD(field as IField):
		emitField Opcodes.PUTFIELD, field

	def INVOKESTATIC(method as IMethod):
		invoke(Opcodes.INVOKESTATIC, method)

	def INVOKEVIRTUAL(method as IMethod):
		invoke(Opcodes.INVOKEVIRTUAL, method)

	def INVOKESPECIAL(method as IMethod):
		invoke(Opcodes.INVOKESPECIAL, method)

	def RETURN():
	   emitInsn(Opcodes.RETURN)

	def ARETURN():
	   emitInsn(Opcodes.ARETURN)

	def POP():
		emitInsn(Opcodes.POP)

	def NEW(type as IType):
		emitTypeInsn(Opcodes.NEW, javaType(type))

	def DUP():
		emitInsn(Opcodes.DUP)

	def ISUB():
		emitInsn(Opcodes.ISUB)

	def IADD():
		emitInsn(Opcodes.IADD)

	def emitVarInsn(opcode as int, index as int):
		_code.visitVarInsn(opcode, index)

	def emitInsn(i as int):
		_code.visitInsn(i)

	def emitIntInsn(opcode as int, value as int):
		_code.visitIntInsn(opcode, value)

	def emitJumpInsn(i as int, label as Label):
		_code.visitJumpInsn(i, label)

	def emitLdcInsn(value):
		_code.visitLdcInsn(value)

	def emitTypeInsn(opcode as int, name as string):
		_code.visitTypeInsn(opcode, name)

	def mark(label as Label):
		_code.visitLabel(label)

	def invoke(opcode as int, method as IMethod):
		_code.visitMethodInsn(
				opcode,
				javaType(method.DeclaringType),
				("<init>" if method isa IConstructor else method.Name),
				javaSignature(method))

	def emitLoadStaticField(declaringType as IType, fieldName as string, fieldType as IType):
		emitField Opcodes.GETSTATIC, declaringType, fieldName, fieldType

	def emitField(opcode as int, field as IField):
		emitField opcode, field.DeclaringType, field.Name, field.Type

	def emitField(opcode as int, declaringType as IType, fieldName as string, fieldType as IType):
		_code.visitFieldInsn(
				opcode,
				javaType(declaringType),
				fieldName,
				typeDescriptor(fieldType))

	def entity(node as Node):
		return GetEntity(node)

	def typeDescriptor(type as IType) as string:
		if type in _primitiveMappings: return _primitiveMappings[type]
		if type.IsArray: return "[" + typeDescriptor(type.GetElementType())
		return "L" + javaType(type) + ";"

	def javaType(type as IType) as string:
		if type in _typeMappings: return _typeMappings[type]
		return type.FullName.Replace('.', '/')

namespace Boojay.Compilation

import System.IO

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

import Boo.PatternMatching

import org.objectweb.asm
import org.objectweb.asm.Type

class BoojayEmitter(AbstractVisitorCompilerStep):

	_classWriter as ClassWriter
	_code as MethodVisitor
	_typeMappings as Hash

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

	def Run():
		Visit(CompileUnit)

	def initializeTypeMappings():
		_typeMappings = {
			typeSystem.ObjectType: "Ljava/lang/Object;",
			typeSystem.StringType: "Ljava/lang/String;",
			typeSystem.BoolType: BOOLEAN_TYPE.getDescriptor(),
			typeSystem.IntType: INT_TYPE.getDescriptor(),
			typeSystem.VoidType: VOID_TYPE.getDescriptor(),
		}

	override def EnterClassDefinition(node as ClassDefinition):
		_classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS)
		_classWriter.visit(
			Opcodes.V1_5,
			Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
			node.FullName,
			null,
			javaName(baseType(node)),
			null)
		return true

	override def LeaveClassDefinition(node as ClassDefinition):
		_classWriter.visitEnd()

		fname = classFullFileName(node)
		ensurePath(fname)
		File.WriteAllBytes(fname, _classWriter.toByteArray())

	override def OnConstructor(node as Constructor):
		pass

	override def OnIfStatement(node as IfStatement):

		elseLabel = Label()
		afterElseLabel = Label()

		emitBranchFalse node.Condition, elseLabel
		emit node.TrueBlock
		if node.FalseBlock is not null:
			GOTO afterElseLabel
		mark elseLabel
		if node.FalseBlock is not null:
			emit node.FalseBlock
			mark afterElseLabel

	def emitBranchFalse(e as Expression, label as Label):
		match e:
			case UnaryExpression(
					Operator: UnaryOperatorType.LogicalNot,
					Operand: condition):
				emitBranchTrue condition, label
			otherwise:
				emit e
				IFEQ label

	def emitBranchTrue(e as Expression, label as Label):
		match e:
			case UnaryExpression(
					Operator: UnaryOperatorType.LogicalNot,
					Operand: condition):
				emitBranchFalse condition, label
			otherwise:
				emit e
				IFNE label

	override def OnWhileStatement(node as WhileStatement):

		testLabel = Label()
		bodyLabel = Label()
		GOTO testLabel
		mark bodyLabel
		emit node.Block
		mark testLabel
		emitBranchTrue node.Condition, bodyLabel

	override def OnMethod(node as Method):
		_code = _classWriter.visitMethod(
					Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC,
					("main" if node.Name == "Main" else node.Name),
					javaSignature(node),
					null,
					null)

		prepareLocalVariables node

		_code.visitCode()

		emit node.Body
		RETURN

		_code.visitMaxs(0, 0)
		_code.visitEnd()

	def prepareLocalVariables(node as Method):
		i = firstLocalIndex(node)
		for local in node.Locals:
			index(local, i)
			++i

	def firstLocalIndex(node as Method):
		if 0 == len(node.Parameters):
			if node.IsStatic: return 0
			return 1
		return lastParameterIndex(node) + 1

	def lastParameterIndex(node as Method):
		param as InternalParameter = entity(node.Parameters[-1])
		return param.Index

	def index(node as Local, index as int):
		node["index"] = index

	def index(entity as InternalLocal) as int:
		return entity.Local["index"]

	override def LeaveExpressionStatement(node as ExpressionStatement):
		discardValueOnStack node.Expression

	def discardValueOnStack(node as Expression):
		mie = node as MethodInvocationExpression
		if mie is null: return

		m = entity(mie.Target) as IMethod
		if m is null: return

		if hasReturnValue(m): POP

	def hasReturnValue(m as IMethod):
		return m.ReturnType is not TypeSystemServices.VoidType

	override def OnReturnStatement(node as ReturnStatement):
		if node.Expression is null:
			RETURN
		else:
			emit node.Expression
			ARETURN

	override def OnMethodInvocationExpression(node as MethodInvocationExpression):

		match entity(node.Target):
			case ctor = IConstructor():
				emitObjectCreation ctor, node
			case method = IMethod():
				emitMethodInvocation method, node
			case builtin = BuiltinFunction():
				emitBuiltinInvocation builtin, node

	def emitBuiltinInvocation(builtin as BuiltinFunction, node as MethodInvocationExpression):
		match builtin.FunctionType:
			case BuiltinFunctionType.Eval:
				emitEval node

	def emitEval(node as MethodInvocationExpression):
		for e in node.Arguments.ToArray()[:-1]:
			emit e
			discardValueOnStack e
		emit node.Arguments[-1]

	def emitMethodInvocation(method as IMethod, node as MethodInvocationExpression):

		if isSpecialIkvmGetter(method):
			emitSpecialIkvmGetter(method)
			return

		emit node.Target
		emit node.Arguments

		if method.IsStatic:
			INVOKESTATIC method
		else:
			INVOKEVIRTUAL method

	def emitObjectCreation(ctor as IConstructor, node as MethodInvocationExpression):
		NEW ctor.DeclaringType
		DUP
		emit node.Arguments
		INVOKESPECIAL ctor

	def emitSpecialIkvmGetter(method as IMethod):
	"""
	in the ikvm version of GNU.ClassPath the
	console streams are mapped to properties
	where in java they should be treated as static fields
	"""
		emitLoadStaticField(
			method.DeclaringType,
			stripGetterPrefix(method.Name),
			method.ReturnType)

	def isSpecialIkvmGetter(method as IMethod):
		return (method.IsStatic
			and method.DeclaringType.FullName == "java.lang.System"
			and method.Name in ("get_out", "get_in", "get_err"))

	override def OnBinaryExpression(node as BinaryExpression):
		match node.Operator:
			case BinaryOperatorType.Assign:
				emitAssignment node
			case BinaryOperatorType.Subtraction:
				emitSubtraction node
			case BinaryOperatorType.Addition:
				emitAddition node

	def emitAddition(node as BinaryExpression):
		emit node.Left
		emit node.Right
		IADD

	def emitSubtraction(node as BinaryExpression):
		emit node.Left
		emit node.Right
		ISUB

	def emitAssignment(node as BinaryExpression):
		match node.Left:
			case memberRef = MemberReferenceExpression():
				match entity(memberRef):
                    case field = IField(IsStatic: false):
                    	emit memberRef.Target
                    	PUTFIELD field
			case reference = ReferenceExpression():
				emit node.Right
				match entity(reference):
					case local = ILocalEntity():
						if not local.Type.IsValueType:
							ASTORE index(local)
						elif isIntegerOrBool(local.Type):
							ISTORE index(local)

	override def OnMemberReferenceExpression(node as MemberReferenceExpression):
		match entity(node):
			case field = IField(IsStatic: true):
				GETSTATIC field
			case field = IField(IsStatic: false):
				emit node.Target
				GETFIELD field
			case IMethod(IsStatic: false):
				emit node.Target
			case IMethod(IsStatic: true):
				pass

	override def OnReferenceExpression(node as ReferenceExpression):
		match entity(node):
			case param = InternalParameter():
				emitLoad param.Type, param.Index
			case local = ILocalEntity():
				emitLoad local.Type, index(local)

	def emitLoad(type as IType, index as int):
		if not type.IsValueType:
			ALOAD index
		elif isIntegerOrBool(type):
			ILOAD index
		else:
			raise "Unsupported type: ${type}"

	def isIntegerOrBool(type as IType):
		return self.TypeSystemServices.IsIntegerOrBool(type)

	def stripGetterPrefix(name as string):
		return name[len("get_"):]

	override def OnStringLiteralExpression(node as StringLiteralExpression):
		LDC node.Value

	override def OnIntegerLiteralExpression(node as IntegerLiteralExpression):
		ICONST node.Value

	override def OnBoolLiteralExpression(node as BoolLiteralExpression):
		if node.Value:
			ICONST_1
		else:
			ICONST_0

	def baseType(node as ClassDefinition):
		return self.GetType(node).BaseType

	typeSystem as JavaTypeSystem:
		get: return self.TypeSystemServices

	def javaSignature(method as IMethod):
		return ("("
			+ join(javaName(p.Type) for p in method.GetParameters(), "")
			+ ")"
			+ javaName(method.ReturnType))

	def javaSignature(node as Method):
		return javaSignature(entity(node) as IMethod)

	def ensurePath(fname as string):
		path = Path.GetDirectoryName(fname)
		if not string.IsNullOrEmpty(path):
			Directory.CreateDirectory(path)

	def classFullFileName(node as TypeDefinition):
		return javaType(entity(node)) + ".class"

	def emit(node as Node):
		Visit(node)

	def emit(nodes as System.Collections.IEnumerable):
		VisitCollection(nodes)

	def LDC(value):
		emitLdcInsn(value)

	def IFEQ(label as Label):
		emitJumpInsn(Opcodes.IFEQ, label)

	def IFNE(label as Label):
        emitJumpInsn(Opcodes.IFNE, label)

	def GOTO(label as Label):
		emitJumpInsn(Opcodes.GOTO, label)

	def ILOAD(index as int):
		emitVarInsn(Opcodes.ILOAD, index)

	def ICONST(value as int):
		if value >= -1 and value <= 5:
			emitInsn(iconstOpcodeFor(value))
		elif value >= -127 and value <= 127:
			emitIntInsn Opcodes.BIPUSH, value
		else:
			emitIntInsn Opcodes.SIPUSH, value

	def ICONST_0():
		emitInsn(Opcodes.ICONST_0)

	def ICONST_1():
		emitInsn(Opcodes.ICONST_1)

	def iconstOpcodeFor(value as int):
		if value == 0: return Opcodes.ICONST_0
		if value == 1: return Opcodes.ICONST_1
		if value == 2: return Opcodes.ICONST_2
		if value == -1: return Opcodes.ICONST_M1
		raise System.ArgumentException("value")

	def ISTORE(index as int):
		emitVarInsn(Opcodes.ISTORE, index)

	def ALOAD(index as int):
		emitVarInsn(Opcodes.ALOAD, index)

	def ASTORE(index as int):
		emitVarInsn(Opcodes.ASTORE, index)

	def GETSTATIC(field as IField):
		emitLoadStaticField(field.DeclaringType, field.Name, field.Type)

	def GETFIELD(field as IField):
		emitField Opcodes.GETFIELD, field

	def PUTFIELD(field as IField):
		emitField Opcodes.PUTFIELD, field

	def INVOKESTATIC(method as IMethod):
		invoke(Opcodes.INVOKESTATIC, method)

	def INVOKEVIRTUAL(method as IMethod):
		invoke(Opcodes.INVOKEVIRTUAL, method)

	def INVOKESPECIAL(method as IMethod):
		invoke(Opcodes.INVOKESPECIAL, method)

	def RETURN():
	   emitInsn(Opcodes.RETURN)

	def ARETURN():
	   emitInsn(Opcodes.ARETURN)

	def POP():
		emitInsn(Opcodes.POP)

	def NEW(type as IType):
		emitTypeInsn(Opcodes.NEW, javaType(type))

	def DUP():
		emitInsn(Opcodes.DUP)

	def ISUB():
		emitInsn(Opcodes.ISUB)

	def IADD():
		emitInsn(Opcodes.IADD)

	def emitVarInsn(opcode as int, index as int):
		_code.visitVarInsn(opcode, index)

	def emitInsn(i as int):
		_code.visitInsn(i)

	def emitIntInsn(opcode as int, value as int):
		_code.visitIntInsn(opcode, value)

	def emitJumpInsn(i as int, label as Label):
		_code.visitJumpInsn(i, label)

	def emitLdcInsn(value):
		_code.visitLdcInsn(value)

	def emitTypeInsn(opcode as int, name as string):
		_code.visitTypeInsn(opcode, name)

	def mark(label as Label):
		_code.visitLabel(label)

	def invoke(opcode as int, method as IMethod):
		_code.visitMethodInsn(
				opcode,
				javaType(method.DeclaringType),
				("<init>" if method isa IConstructor else method.Name),
				javaSignature(method))

	def emitLoadStaticField(declaringType as IType, fieldName as string, fieldType as IType):
		emitField Opcodes.GETSTATIC, declaringType, fieldName, fieldType

	def emitField(opcode as int, field as IField):
		emitField opcode, field.DeclaringType, field.Name, field.Type

	def emitField(opcode as int, declaringType as IType, fieldName as string, fieldType as IType):
		_code.visitFieldInsn(
				opcode,
				javaType(declaringType),
				fieldName,
				javaName(fieldType))

	def entity(node as Node):
		return GetEntity(node)

	def javaName(type as IType) as string:
		if type in _typeMappings: return _typeMappings[type]
		if type.IsArray: return "[" + javaName(type.GetElementType())
		return "L" + javaType(type) + ";"

	def javaType(type as IType) as string:
		return type.FullName.Replace('.', '/')


fix instructions to reflect new script name

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

// By Doug Holton. More stuff added by David Piepgrass.
// For help, please see the help string below.
import System
import System.IO
import System.Xml.Serialization from System.Xml
import Boo.Lang.Compiler from Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Pipelines
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Ast.Visitors
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.Steps
import System.Reflection

[System.Runtime.CompilerServices.CompilerGlobalScopeAttribute]
class Globals:
	static help = """
This script visits the AST structure after each step in the compile
process
and converts it to XML or back to boo syntax. If there are visible
differences since the previous step, it saves the output to a file in a

folder named after the command-line arguments (name of source file plus

options).

How to use:

booi path/to/showcompilersteps.boo [-xml | (-ent | -exp | -nodes) [-short]
[-bind]]
                           path/to/your/script.boo

-xml: generate XML representation of AST
-ent: show entity type names that are associated with AST nodes
(node.Entity)
-exp: show entity type names and expression types (node.ExpressionType)
-nodes: show entity type names and expression types, and for each typed

        expression, also show the AST type (node.GetType())
-bind: show binding information contained in entities
-short: abbreviate the output so that lines hopefully fit on your
screen.

You can also use the "-r:assembly.dll" flag to add assembly references.

ShowSteps will generate a folder in the current directory named after
the
input file and the options you specified. It generates copies of the
script
after each compiler step, and puts them in that folder.

If you use -exp -nodes -bind, the output can get pretty long and
confusing.
For example, a simple expression like "_x", that refers to a variable
_x in
the current class, eventually expands to a the following (all on one
line):

  <InternalField MemberReferenceExpression=double
Bind=Field:Ns.MyClass._x>
    <InternalMethod SelfLiteralExpression=Foo.B
Bind=Method:Ns.MyClass.MyFn>
    self</InternalMethod>._x
  </InternalField>

The -short command-line option will use an abbreviated syntax like
this:

  <ItlField MemberRefrExpr=double @F:Ns.MyClass._x>
    <ItlMethod SelfLiteralExpr=Foo.B @M:Ns.MyClass.MyFn>
    self</IM>._x
  </IF>

Here's how to understand it. First of all, of course, it's not really
XML,
it's just an XML-like notation. If you have a text editor that can do
XML
syntax highlighting, use it. Second, notice that a reference to "self"
has
been added. Third, the outer tag (InternalField) describes the whole
expression, "self._x", whereas the inner tag (InternalMethod) describes
only the "self" part. The tags have the following syntax:

  <E N=T Bind=S:P> where

  N: Class of AST node. For example, "MemberReferenceExpression" refers
     to the Boo.Lang.Compiler.Ast.MemberReferenceExpression class.
  T: The value of node.ExpressionType.ToString(), e.g. int
  E: Type of entity associated with the node, or "_" if the node has no
     entity. For example, "InternalField" actually refers to the
     Boo.Lang.Compiler.TypeSystem.InternalField class. It seems that an
     entity's main purpose is to hold binding information.
  S: The entity's EntityType (although I don't actually know what it's
for.)
     If the EntityType is EntityType.Type, which is the most common
case,
     then S is omitted.
  P: Binding Path. For example, X.Y.Z might represent a variable or
method
     "Z" in class "Y" in namespace "X".

A tag is not printed at all if there is no entity nor data type
associated with a node. That's why you don't see very many tags during
the first compiler steps. The "N=T" part is printed only if the node is
an Expression and it has a a known data type; the Bind=S:P part is only

printed if binding information is available.
	"""
	static format = "boo" //or "xml" //format for output
	static foldername = "compilersteps" //folder where files are saved
	static showents = false  //whether to print entity types
	static showexp = false //show expression types as well
	static shownodetypes = false
	static shorten = false
	static showbindings = false
	//used internally:
	static savefolder as string
	static n = 0
	static laststep as string

//basic boo printer visitor, but adds comments if a node is synthetic (generated
//by the compiler instead of the user).
class BooSyntheticPrinterVisitor(BooPrinterVisitor):
	def constructor(writer as TextWriter):
		super(writer)
	override def Visit(node as Node) as bool:
		if node is not null and node.IsSynthetic:
			WriteIndented("// synthetic")
			WriteLine()
			WriteIndented("")
		return super(node)

class BooTypePrinterVisitor(BooPrinterVisitor):
	_showexp = false
	_shownodetypes = false
	_shorten = false
	_showbindings = false
	def constructor(writer as TextWriter, show_expressions as bool, shownodetypes as bool, shorten as bool, showbindings as bool):
		super(writer)
		_showexp = show_expressions
		_shownodetypes = shownodetypes
		_shorten = shorten
		_showbindings = showbindings

	override def Visit(node as Node) as bool:
		return true if node is null
		if node.IsSynthetic:
			WriteIndented("// synthetic")
			WriteLine()

		WriteIndented() // Automatically indent iff starting a new line
		tagname = ""

		entity = TypeSystemServices.GetOptionalEntity(node) // aka node.Entity
		if entity is not null:
			tagname = ShortName(entity.GetType())
			s = "<"
			s += tagname
			s += ExtraJunk(node)
			s += ">"
			Write(s)
			if _shorten:
				tagname = InitialsOf(tagname)
		elif _showexp or _showbindings:
			junk = ExtraJunk(node)
			if junk.Length > 0:
				tagname = "_"
				s = "<_${junk}>"
				Write(s)

		result = super(node)
		if tagname != "":
			WriteIndented("</"+tagname+">")
		return result

	def ShortName(t as object):
		t2 = t.ToString(). \
			Replace("Boo.Lang.Compiler.TypeSystem.",""). \
			Replace("Boo.Lang.Compiler.Ast.","")
		return t2 unless _shorten
		return t2. \
			Replace("Expression", "Expr"). \
			Replace("Reference", "Refr"). \
			Replace("Internal", "Itl").Replace("External", "Xtl")

	def InitialsOf(s as string):
		s2 = System.Text.StringBuilder()
		for ch in s:
			if ch >= char('A') and ch <= char('Z'):
				s2.Append(ch)
		if s2.Length>0:
			return s2.ToString()
		else:
			return s

	def ExtraJunk(node as Node):
		s = System.Text.StringBuilder()
		if _showexp:
			exp = node as Expression
			if exp is not null and exp.ExpressionType is not null:
				if _shownodetypes:
					s.Append(" ")
					s.Append(ShortName(node.GetType()))
					s.Append("=")
				elif _shorten:
					s.Append(":")
				else:
					s.Append(" EType=")
				s.Append(ShortName(exp.ExpressionType.ToString()))

		if _showbindings:
			entity = TypeSystemServices.GetOptionalEntity(node) // aka node.Entity
			if entity is not null:
				if _shorten:
					s.Append(" @")
				else:
					s.Append(" Bind=")
				if entity.EntityType != EntityType.Type:
					if _shorten:
						s.Append(InitialsOf(entity.EntityType.ToString()))
					else:
						s.Append(entity.EntityType.ToString())
					s.Append(char(':'))
				s.Append(entity.FullName)
		return s.ToString()

def PrintAST([required]result as CompilerContext, [required]o as TextWriter):
	astobject = result.CompileUnit
	try:
		s = XmlSerializer( astobject.GetType() )
		s.Serialize( o, astobject )
	except e:
		print
		print e.GetType(), ":", e.Message

def AfterStep(sender, e as CompilerStepEventArgs):
	++n
	stepname = e.Step.ToString().Replace("Boo.Lang.Parser.","").Replace("Boo.Lang.Compiler.Steps.","")

	tempfile = Path.GetTempFileName()
	using temp = StreamWriter(tempfile):
		if format == "xml":
			PrintAST(e.Context, temp)
		else:
			try:
				printer as BooPrinterVisitor
				if showents:
					printer = BooTypePrinterVisitor(temp, showexp, shownodetypes, shorten, showbindings)
				else:
					printer = BooSyntheticPrinterVisitor(temp)
				printer.Print(e.Context.CompileUnit)
			except e:
				print e.Message + "\n" + e.StackTrace

	using r = StreamReader(tempfile):
		thisstep = r.ReadToEnd()

	filename = string.Format("STEP{0:D2}-{1}.{2}", n, stepname, format)

	if thisstep != laststep:
		File.Move(tempfile, Path.Combine(savefolder, filename))
		laststep = thisstep
		print string.Format("STEP{0:D2}-{1}: SAVED TO {2} FILE.", n, stepname, format.ToUpper())
	else:
		File.Delete(tempfile)
		print string.Format("STEP{0:D2}-{1}: NO CHANGE TO AST.", n, stepname)

def LoadAssembly(assemblyName as string) as Assembly:
	reference as Assembly
	if File.Exists(Path.GetFullPath(assemblyName)):
		reference = Assembly.LoadFrom(Path.GetFullPath(assemblyName))
	if reference is null:
		reference = Assembly.LoadWithPartialName(assemblyName)
		if reference is null:
			raise ApplicationException(
				ResourceManager.Format("BooC.UnableToLoadAssembly",
							assemblyName))
	return reference

///////////////////////////////////////////////////

if len(argv) == 0:
	print help
	return

compiler = BooCompiler()

compiler.Parameters.Pipeline = Compile()
compiler.Parameters.Pipeline.AfterStep += AfterStep

foldername_base = foldername_extra = ""

for arg in argv:

	if arg[0:3] == "-r:":
		compiler.Parameters.References.Add(LoadAssembly(arg[3:]))
		continue
	elif arg == "-xml":
		format = "xml"
	elif arg == "-ent":
		showents = true
	elif arg == "-exp":
		showents = true
		showexp = true
	elif arg == "-ducky":
		compiler.Parameters.Ducky = true
	elif arg == "-nodes":
		showents = true
		showexp = true
		shownodetypes = true
	elif arg == "-short":
		shorten = true
	elif arg == "-bind":
		showbindings = true
	else:
		compiler.Parameters.Input.Add(FileInput(arg))
		foldername_base += /^(.*?[\/\\])*([^\\\/]+?)(\.[^.\\\/]*)?$/.Match(arg).Groups[2]
		continue
	foldername_extra += " " + arg

foldername = foldername_base + foldername_extra

//delete old folder if running more than once:
if Directory.Exists(foldername):
	Directory.Delete(foldername, true)

savedir = Directory.CreateDirectory(foldername)
if savedir is null or not Directory.Exists(foldername):
	print "The directory '${foldername}' could not be created."
	return

savefolder = savedir.FullName

try:
	print
	print "See boo/src/Boo.Lang.Compiler/Steps/ for the source code for these steps."
	print
	result = compiler.Run()
	if len(result.Errors) > 0:
		print "\nThere were ${len(result.Errors)} errors compiling the boo file(s)"
		print result.Errors.ToString(true)
	else:
		print "\nSuccessful: See the files under: '${savefolder}'"
except e:
	print e.GetType(), ":", e.Message

// By Doug Holton. More stuff added by David Piepgrass.
// For help, please see the help string below.
import System
import System.IO
import System.Xml.Serialization from System.Xml
import Boo.Lang.Compiler from Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Pipelines
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Ast.Visitors
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.Steps
import System.Reflection

[System.Runtime.CompilerServices.CompilerGlobalScopeAttribute]
class Globals:
	static help = """
This script visits the AST structure after each step in the compile
process
and converts it to XML or back to boo syntax. If there are visible
differences since the previous step, it saves the output to a file in a

folder named after the command-line arguments (name of source file plus

options).

How to use:

booi path/to/showsteps.boo [-xml | (-ent | -exp | -nodes) [-short]
[-bind]]
                           path/to/your/script.boo

-xml: generate XML representation of AST
-ent: show entity type names that are associated with AST nodes
(node.Entity)
-exp: show entity type names and expression types (node.ExpressionType)
-nodes: show entity type names and expression types, and for each typed

        expression, also show the AST type (node.GetType())
-bind: show binding information contained in entities
-short: abbreviate the output so that lines hopefully fit on your
screen.

You can also use the "-r:assembly.dll" flag to add assembly references.

ShowSteps will generate a folder in the current directory named after
the
input file and the options you specified. It generates copies of the
script
after each compiler step, and puts them in that folder.

If you use -exp -nodes -bind, the output can get pretty long and
confusing.
For example, a simple expression like "_x", that refers to a variable
_x in
the current class, eventually expands to a the following (all on one
line):

  <InternalField MemberReferenceExpression=double
Bind=Field:Ns.MyClass._x>
    <InternalMethod SelfLiteralExpression=Foo.B
Bind=Method:Ns.MyClass.MyFn>
    self</InternalMethod>._x
  </InternalField>

The -short command-line option will use an abbreviated syntax like
this:

  <ItlField MemberRefrExpr=double @F:Ns.MyClass._x>
    <ItlMethod SelfLiteralExpr=Foo.B @M:Ns.MyClass.MyFn>
    self</IM>._x
  </IF>

Here's how to understand it. First of all, of course, it's not really
XML,
it's just an XML-like notation. If you have a text editor that can do
XML
syntax highlighting, use it. Second, notice that a reference to "self"
has
been added. Third, the outer tag (InternalField) describes the whole
expression, "self._x", whereas the inner tag (InternalMethod) describes
only the "self" part. The tags have the following syntax:

  <E N=T Bind=S:P> where

  N: Class of AST node. For example, "MemberReferenceExpression" refers
     to the Boo.Lang.Compiler.Ast.MemberReferenceExpression class.
  T: The value of node.ExpressionType.ToString(), e.g. int
  E: Type of entity associated with the node, or "_" if the node has no
     entity. For example, "InternalField" actually refers to the
     Boo.Lang.Compiler.TypeSystem.InternalField class. It seems that an
     entity's main purpose is to hold binding information.
  S: The entity's EntityType (although I don't actually know what it's
for.)
     If the EntityType is EntityType.Type, which is the most common
case,
     then S is omitted.
  P: Binding Path. For example, X.Y.Z might represent a variable or
method
     "Z" in class "Y" in namespace "X".

A tag is not printed at all if there is no entity nor data type
associated with a node. That's why you don't see very many tags during
the first compiler steps. The "N=T" part is printed only if the node is
an Expression and it has a a known data type; the Bind=S:P part is only

printed if binding information is available.
	"""
	static format = "boo" //or "xml" //format for output
	static foldername = "compilersteps" //folder where files are saved
	static showents = false  //whether to print entity types
	static showexp = false //show expression types as well
	static shownodetypes = false
	static shorten = false
	static showbindings = false
	//used internally:
	static savefolder as string
	static n = 0
	static laststep as string

//basic boo printer visitor, but adds comments if a node is synthetic (generated
//by the compiler instead of the user).
class BooSyntheticPrinterVisitor(BooPrinterVisitor):
	def constructor(writer as TextWriter):
		super(writer)
	override def Visit(node as Node) as bool:
		if node is not null and node.IsSynthetic:
			WriteIndented("// synthetic")
			WriteLine()
			WriteIndented("")
		return super(node)

class BooTypePrinterVisitor(BooPrinterVisitor):
	_showexp = false
	_shownodetypes = false
	_shorten = false
	_showbindings = false
	def constructor(writer as TextWriter, show_expressions as bool, shownodetypes as bool, shorten as bool, showbindings as bool):
		super(writer)
		_showexp = show_expressions
		_shownodetypes = shownodetypes
		_shorten = shorten
		_showbindings = showbindings

	override def Visit(node as Node) as bool:
		return true if node is null
		if node.IsSynthetic:
			WriteIndented("// synthetic")
			WriteLine()

		WriteIndented() // Automatically indent iff starting a new line
		tagname = ""

		entity = TypeSystemServices.GetOptionalEntity(node) // aka node.Entity
		if entity is not null:
			tagname = ShortName(entity.GetType())
			s = "<"
			s += tagname
			s += ExtraJunk(node)
			s += ">"
			Write(s)
			if _shorten:
				tagname = InitialsOf(tagname)
		elif _showexp or _showbindings:
			junk = ExtraJunk(node)
			if junk.Length > 0:
				tagname = "_"
				s = "<_${junk}>"
				Write(s)

		result = super(node)
		if tagname != "":
			WriteIndented("</"+tagname+">")
		return result

	def ShortName(t as object):
		t2 = t.ToString(). \
			Replace("Boo.Lang.Compiler.TypeSystem.",""). \
			Replace("Boo.Lang.Compiler.Ast.","")
		return t2 unless _shorten
		return t2. \
			Replace("Expression", "Expr"). \
			Replace("Reference", "Refr"). \
			Replace("Internal", "Itl").Replace("External", "Xtl")

	def InitialsOf(s as string):
		s2 = System.Text.StringBuilder()
		for ch in s:
			if ch >= char('A') and ch <= char('Z'):
				s2.Append(ch)
		if s2.Length>0:
			return s2.ToString()
		else:
			return s

	def ExtraJunk(node as Node):
		s = System.Text.StringBuilder()
		if _showexp:
			exp = node as Expression
			if exp is not null and exp.ExpressionType is not null:
				if _shownodetypes:
					s.Append(" ")
					s.Append(ShortName(node.GetType()))
					s.Append("=")
				elif _shorten:
					s.Append(":")
				else:
					s.Append(" EType=")
				s.Append(ShortName(exp.ExpressionType.ToString()))

		if _showbindings:
			entity = TypeSystemServices.GetOptionalEntity(node) // aka node.Entity
			if entity is not null:
				if _shorten:
					s.Append(" @")
				else:
					s.Append(" Bind=")
				if entity.EntityType != EntityType.Type:
					if _shorten:
						s.Append(InitialsOf(entity.EntityType.ToString()))
					else:
						s.Append(entity.EntityType.ToString())
					s.Append(char(':'))
				s.Append(entity.FullName)
		return s.ToString()

def PrintAST([required]result as CompilerContext, [required]o as TextWriter):
	astobject = result.CompileUnit
	try:
		s = XmlSerializer( astobject.GetType() )
		s.Serialize( o, astobject )
	except e:
		print
		print e.GetType(), ":", e.Message

def AfterStep(sender, e as CompilerStepEventArgs):
	++n
	stepname = e.Step.ToString().Replace("Boo.Lang.Parser.","").Replace("Boo.Lang.Compiler.Steps.","")

	tempfile = Path.GetTempFileName()
	using temp = StreamWriter(tempfile):
		if format == "xml":
			PrintAST(e.Context, temp)
		else:
			try:
				printer as BooPrinterVisitor
				if showents:
					printer = BooTypePrinterVisitor(temp, showexp, shownodetypes, shorten, showbindings)
				else:
					printer = BooSyntheticPrinterVisitor(temp)
				printer.Print(e.Context.CompileUnit)
			except e:
				print e.Message + "\n" + e.StackTrace

	using r = StreamReader(tempfile):
		thisstep = r.ReadToEnd()

	filename = string.Format("STEP{0:D2}-{1}.{2}", n, stepname, format)

	if thisstep != laststep:
		File.Move(tempfile, Path.Combine(savefolder, filename))
		laststep = thisstep
		print string.Format("STEP{0:D2}-{1}: SAVED TO {2} FILE.", n, stepname, format.ToUpper())
	else:
		File.Delete(tempfile)
		print string.Format("STEP{0:D2}-{1}: NO CHANGE TO AST.", n, stepname)

def LoadAssembly(assemblyName as string) as Assembly:
	reference as Assembly
	if File.Exists(Path.GetFullPath(assemblyName)):
		reference = Assembly.LoadFrom(Path.GetFullPath(assemblyName))
	if reference is null:
		reference = Assembly.LoadWithPartialName(assemblyName)
		if reference is null:
			raise ApplicationException(
				ResourceManager.Format("BooC.UnableToLoadAssembly",
							assemblyName))
	return reference

///////////////////////////////////////////////////

if len(argv) == 0:
	print help
	return

compiler = BooCompiler()

compiler.Parameters.Pipeline = Compile()
compiler.Parameters.Pipeline.AfterStep += AfterStep

foldername_base = foldername_extra = ""

for arg in argv:

	if arg[0:3] == "-r:":
		compiler.Parameters.References.Add(LoadAssembly(arg[3:]))
		continue
	elif arg == "-xml":
		format = "xml"
	elif arg == "-ent":
		showents = true
	elif arg == "-exp":
		showents = true
		showexp = true
	elif arg == "-ducky":
		compiler.Parameters.Ducky = true
	elif arg == "-nodes":
		showents = true
		showexp = true
		shownodetypes = true
	elif arg == "-short":
		shorten = true
	elif arg == "-bind":
		showbindings = true
	else:
		compiler.Parameters.Input.Add(FileInput(arg))
		foldername_base += /^(.*?[\/\\])*([^\\\/]+?)(\.[^.\\\/]*)?$/.Match(arg).Groups[2]
		continue
	foldername_extra += " " + arg

foldername = foldername_base + foldername_extra

//delete old folder if running more than once:
if Directory.Exists(foldername):
	Directory.Delete(foldername, true)

savedir = Directory.CreateDirectory(foldername)
if savedir is null or not Directory.Exists(foldername):
	print "The directory '${foldername}' could not be created."
	return

savefolder = savedir.FullName

try:
	print
	print "See boo/src/Boo.Lang.Compiler/Steps/ for the source code for these steps."
	print
	result = compiler.Run()
	if len(result.Errors) > 0:
		print "\nThere were ${len(result.Errors)} errors compiling the boo file(s)"
		print result.Errors.ToString(true)
	else:
		print "\nSuccessful: See the files under: '${savefolder}'"
except e:
	print e.GetType(), ":", e.Message


fixed mixed indentation in booish

fixed mixed indentation in booish

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

import System
import System.Diagnostics
import Boo.Lang.Interpreter

console = InteractiveInterpreterConsole()

loadRequests = System.Collections.Generic.List[of string]()

for arg in argv:
	if arg == "--print-modules" or arg == "-print-modules":
		console.PrintModules = true
	if arg == "--debug" or arg == "-debug":
		Debug.Listeners.Add(TextWriterTraceListener(Console.Out))
	if arg == "-w":
		console.ShowWarnings = true
	if arg.StartsWith("-r:"):
		loadRequests.Add(arg.Substring(3))
	if arg == "--nologo" or arg == "-nologo":
		nologo = true
	if not arg.StartsWith("-"):
		loadRequests.Add(arg)

console.DisplayLogo() unless nologo

for req in loadRequests:
	console.Load(req)

console.Eval("import Boo.Lang.Interpreter.Builtins")
console.ReadEvalPrintLoop()


fix to pass on .net 2

fix to pass on .net 2

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

import System
import NUnit.Framework

def foo():
	return "foo"

if Environment.Version < Version(2, 0):
	d1 as Delegate = foo
	Assert.AreEqual("foo", d1.DynamicInvoke(null))

	d2 as MulticastDelegate = foo
	Assert.AreEqual("foo", d2.DynamicInvoke(null))

d3 as ICallable = foo
Assert.AreEqual("foo", d3())

import System
import NUnit.Framework

def foo():
	return "foo"

d1 as Delegate = foo
Assert.AreEqual("foo", d1.DynamicInvoke(null))

d2 as MulticastDelegate = foo
Assert.AreEqual("foo", d2.DynamicInvoke(null))

d3 as ICallable = foo
Assert.AreEqual("foo", d3())


eachFile => forEachFileIn

eachFile => forEachFileIn

#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.Useful.IO

import System
import System.IO
import System.Collections
import System.Collections.Generic

def forEachFileIn([required] topDir as string, [required] action as Action of string):
	for fname in Directory.GetFiles(topDir):
		action(fname)
	for subDir in Directory.GetDirectories(topDir):
		forEachFileIn(subDir, action)

def forEachFileIn([required] topDir as string, [required] fileGlob as string, [required] action as Action of string):
	for fname in Directory.GetFiles(topDir, fileGlob):
		action(fname)
	for subDir in Directory.GetDirectories(topDir):
		forEachFileIn(subDir, fileGlob, action)

def listFiles([required] top as string) as string*:
	for fname in Directory.GetFiles(top):
		yield fname
	for subDir in Directory.GetDirectories(top):
		for fname in listFiles(subDir):
			yield fname

def walk([required] top as string) as (object)*:
	files = Directory.GetFiles(top)
	dirs  = Directory.GetDirectories(top)
	yield (top, dirs, files)
	for dir in dirs:
		for t, d, f in walk(dir):
			yield (t, d, f)

#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.Useful.IO

import System.IO
import System.Collections
import System.Collections.Generic

callable FileAction(fname as string)

def eachFile([required] top as string, [required] action as FileAction):
	for fname in Directory.GetFiles(top):
		action(fname)
	for subDir in Directory.GetDirectories(top):
		eachFile(subDir, action)

def listFiles([required] top as string) as IEnumerable[of string]:
	for fname in Directory.GetFiles(top):
		yield fname
	for subDir in Directory.GetDirectories(top):
		for fname in listFiles(subDir):
			yield fname

def walk([required] top as string) as IEnumerable:
	files = Directory.GetFiles(top)
	dirs  = Directory.GetDirectories(top)
	yield (top, dirs, files)
	for dir in dirs:
		for t, d, f in walk(dir):
			yield (t, d, f)