Strip xml docs.

Strip xml docs.

namespace UnityScript.MonoDevelop.Completion

import System
import System.Collections.Generic

import UnityScript
import UnityScript.MonoDevelop
import UnityScript.MonoDevelop.ProjectModel

import MonoDevelop.Core
import MonoDevelop.Projects
import MonoDevelop.Projects.Dom.Parser
import MonoDevelop.Ide.Gui
import MonoDevelop.Ide.Gui.Content
import MonoDevelop.Ide.CodeCompletion

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

class UnityScriptEditorCompletion(CompletionTextEditorExtension):

	_dom as ProjectDom
	_resolver as UnityScriptTypeResolver
	_project as DotNetProject

	override def Initialize():
		super()
		_dom = ProjectDomService.GetProjectDom(Document.Project) or ProjectDomService.GetFileDom(Document.FileName)
		InstallUnityScriptSyntaxModeIfNeeded()
		_resolver = UnityScriptTypeResolver()
		_project = Document.Project as DotNetProject
		InitializeProjectReferences()

	def InitializeProjectReferences():
		if _project is null:
			return

		for reference in _project.References:
			if ReferenceType.Project != reference.ReferenceType:
				_resolver.AddReference(reference.Reference)

	def InstallUnityScriptSyntaxModeIfNeeded():
		view = Document.GetContent[of MonoDevelop.SourceEditor.SourceEditorView]()
		return if view is null

		mimeType = UnityScriptParser.MimeType
		return if view.Document.SyntaxMode.MimeType == mimeType

		mode = Mono.TextEditor.Highlighting.SyntaxModeService.GetSyntaxMode(mimeType)
		if mode is not null:
			view.Document.SyntaxMode = mode
		else:
			LoggingService.LogWarning(GetType() + " could not get SyntaxMode for mimetype '" + mimeType + "'.")

	override def ExtendsEditor(doc as MonoDevelop.Ide.Gui.Document, editor as IEditableTextBuffer):
		return IsUnityScriptFile(doc.Name)

	override def HandleCodeCompletion(context as CodeCompletionContext, completionChar as char):
#		print "HandleCodeCompletion(${context.ToString()}, ${completionChar.ToString()})"

		match completionChar.ToString():
			case ' ':
				lineText = GetLineText(context.TriggerLine).TrimStart()
				if not lineText.StartsWith("import "):
					return null

				return ImportCompletionDataFor('')

			case '.':
				lineText = GetLineText(context.TriggerLine)
				lineLength = lineText.Length
				lineText = lineText.TrimStart()
				trimmedLength = lineLength - lineText.Length
				if lineText.StartsWith("import "):
					nameSpace = lineText[len("import "):context.TriggerLineOffset-(2+trimmedLength)].Trim()
					return ImportCompletionDataFor(nameSpace)

				result = null as CompletionDataList
				text = string.Format ("{0}{1} {2}", Document.TextEditor.GetText (0, context.TriggerOffset),
				                                    CompletionFinder.CompletionToken,
				                                    Document.TextEditor.GetText (context.TriggerOffset, Document.TextEditor.TextLength))
				# print text
				_resolver.Input.Clear()
				_resolver.Input.Add(StringInput("completion text", text))

				result = CompletionDataList()

				_resolver.ResolveAnd() do (type as IType):
					resultHash = Dictionary[of string,string]()
					for member in type.GetMembers():
						# print member
						resultHash[SanitizeMemberName(type,member)] = GetIconForMember(member)
					for pair in resultHash:
						unless string.IsNullOrEmpty(pair.Key) or (4 < pair.Key.Length and /^[gs]et_/.Matches(pair.Key) and resultHash.ContainsKey(pair.Key[4:])):
							result.Add(pair.Key, pair.Value)

				return result

			otherwise:
				return null

	def ImportCompletionDataFor(nameSpace as string):
#		print "ImportCompletionDataFor(${nameSpace})"

		result = CompletionDataList()
		for member in _dom.GetNamespaceContents(nameSpace, true, true):
			result.Add(member.Name, member.StockIcon)
		return result

	def GetLineText(line as int):
		return Document.TextEditor.GetLineText(line)

	def GetIconForMember(member as IEntity):
		match member.EntityType:
			case EntityType.BuiltinFunction:
				return Stock.Method
			case EntityType.Constructor:
				return Stock.Method
			case EntityType.Method:
				return Stock.Method
			case EntityType.Local:
				return Stock.Field
			case EntityType.Field:
				return Stock.Field
			case EntityType.Property:
				return Stock.Property
			case EntityType.Event:
				return Stock.Event
			otherwise:
				return Stock.Literal

	def SanitizeMemberName(type as IType,member as IEntity) as string:
		name = member.Name
		if (0 <= (lastDot = name.LastIndexOf('.'))):
			name = name[lastDot+1:]
		if ("constructor" == name):
			name = type.Name
		if (name.StartsWith("internal_", StringComparison.OrdinalIgnoreCase) or name.StartsWith("op_", StringComparison.Ordinal)):
			name = string.Empty
		return name

namespace UnityScript.MonoDevelop.Completion

import System
import System.Collections.Generic

import UnityScript
import UnityScript.MonoDevelop
import UnityScript.MonoDevelop.ProjectModel

import MonoDevelop.Core
import MonoDevelop.Projects
import MonoDevelop.Projects.Dom.Parser
import MonoDevelop.Ide.Gui
import MonoDevelop.Ide.Gui.Content
import MonoDevelop.Ide.CodeCompletion

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

class UnityScriptEditorCompletion(CompletionTextEditorExtension):

	_dom as ProjectDom
	_resolver as UnityScriptTypeResolver
	_project as DotNetProject

	override def Initialize():
		super()
		_dom = ProjectDomService.GetProjectDom(Document.Project) or ProjectDomService.GetFileDom(Document.FileName)
		InstallUnityScriptSyntaxModeIfNeeded()
		_resolver = UnityScriptTypeResolver()
		_project = Document.Project as DotNetProject
		InitializeProjectReferences()

	def InitializeProjectReferences():
		if _project is null:
			return

		for reference in _project.References:
			if ReferenceType.Project != reference.ReferenceType:
				_resolver.AddReference(reference.Reference)

	def InstallUnityScriptSyntaxModeIfNeeded():
		view = Document.GetContent[of MonoDevelop.SourceEditor.SourceEditorView]()
		return if view is null

		mimeType = UnityScriptParser.MimeType
		return if view.Document.SyntaxMode.MimeType == mimeType

		mode = Mono.TextEditor.Highlighting.SyntaxModeService.GetSyntaxMode(mimeType)
		if mode is not null:
			view.Document.SyntaxMode = mode
		else:
			LoggingService.LogWarning(GetType() + " could not get SyntaxMode for mimetype '" + mimeType + "'.")

	override def ExtendsEditor(doc as MonoDevelop.Ide.Gui.Document, editor as IEditableTextBuffer):
		return IsUnityScriptFile(doc.Name)

	override def HandleCodeCompletion(context as CodeCompletionContext, completionChar as char):
#		print "HandleCodeCompletion(${context.ToString()}, ${completionChar.ToString()})"

		match completionChar.ToString():
			case ' ':
				lineText = GetLineText(context.TriggerLine).TrimStart()
				if not lineText.StartsWith("import "):
					return null

				return ImportCompletionDataFor('')

			case '.':
				lineText = GetLineText(context.TriggerLine)
				lineLength = lineText.Length
				lineText = lineText.TrimStart()
				trimmedLength = lineLength - lineText.Length
				if lineText.StartsWith("import "):
					nameSpace = lineText[len("import "):context.TriggerLineOffset-(2+trimmedLength)].Trim()
					return ImportCompletionDataFor(nameSpace)

				result = null as CompletionDataList
				text = string.Format ("{0}{1} {2}", Document.TextEditor.GetText (0, context.TriggerOffset),
				                                    CompletionFinder.CompletionToken,
				                                    Document.TextEditor.GetText (context.TriggerOffset, Document.TextEditor.TextLength))
				# print text
				_resolver.Input.Clear()
				_resolver.Input.Add(StringInput("completion text", text))

				result = CompletionDataList()

				_resolver.ResolveAnd() do (type as IType):
					resultHash = Dictionary[of string,string]()
					for member in type.GetMembers():
						# print member
						resultHash[SanitizeMemberName(type,member)] = GetIconForMember(member)
					for pair in resultHash:
						unless string.IsNullOrEmpty(pair.Key) or (4 < pair.Key.Length and /^[gs]et_/.Matches(pair.Key) and resultHash.ContainsKey(pair.Key[4:])):
							result.Add(pair.Key, pair.Value)

				return result

			otherwise:
				return null

	def ImportCompletionDataFor(nameSpace as string):
#		print "ImportCompletionDataFor(${nameSpace})"

		result = CompletionDataList()
		for member in _dom.GetNamespaceContents(nameSpace, true, true):
			result.Add(member.Name, member.StockIcon)
		return result

	def GetLineText(line as int):
		return Document.TextEditor.GetLineText(line)

	# <summary>
	# Gets the proper stock icon for an IEntity
	# </summary>
	# <param name="member">The member whose icon is wanted</param>
	# <returns>A stock icon string</returns>
	def GetIconForMember(member as IEntity):
		match member.EntityType:
			case EntityType.BuiltinFunction:
				return Stock.Method
			case EntityType.Constructor:
				return Stock.Method
			case EntityType.Method:
				return Stock.Method
			case EntityType.Local:
				return Stock.Field
			case EntityType.Field:
				return Stock.Field
			case EntityType.Property:
				return Stock.Property
			case EntityType.Event:
				return Stock.Event
			otherwise:
				return Stock.Literal

	# <summary>
	# Sanitizes the member names we get from the compiler pipeline
	# </summary>
	# <param name="type">The type to which the member belongs</param>
	# <param name="member">The member whose name should be sanitized</param>
	# <returns>The sanitized name (empty for invalid)</returns>
	def SanitizeMemberName(type as IType,member as IEntity) as string:
		name = member.Name
		if (0 <= (lastDot = name.LastIndexOf('.'))):
			name = name[lastDot+1:]
		if ("constructor" == name):
			name = type.Name
		if (name.StartsWith("internal_", StringComparison.OrdinalIgnoreCase) or name.StartsWith("op_", StringComparison.Ordinal)):
			name = string.Empty
		return name


use DepthFirstTransformer instead

use DepthFirstTransformer instead

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

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

class WithMacro(AbstractAstMacro):

	private class NameExpander(DepthFirstTransformer):

		_inst as ReferenceExpression

		def constructor(inst as ReferenceExpression):
			_inst = inst

		override def OnReferenceExpression(node as ReferenceExpression):
			// if the name of the reference begins with '_'
			// then convert the reference to a member reference
			// of the provided instance
			if node.Name.StartsWith('_'):
				// create the new member reference and set it up
				mre = MemberReferenceExpression(node.LexicalInfo)
				mre.Name = node.Name[1:]
				mre.Target = _inst.CloneNode()

				// replace the original reference in the AST
				// with the new member-reference
				ReplaceCurrentNode(mre)

	override def Expand(macro as MacroStatement) as Statement:
		assert 1 == macro.Arguments.Count
		assert macro.Arguments[0] isa ReferenceExpression

		inst = macro.Arguments[0] as ReferenceExpression

		// convert all _<ref> to inst.<ref>
		block = macro.Block
		ne = NameExpander(inst)
		ne.Visit(block)
		return block

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

class WithMacro(AbstractAstMacro):

	private class NameExpander(DepthFirstVisitor):

		_inst as ReferenceExpression

		def constructor(inst as ReferenceExpression):
			_inst = inst

		override def OnReferenceExpression(node as ReferenceExpression):
			// if the name of the reference begins with '_'
			// then convert the reference to a member reference
			// of the provided instance
			if node.Name.StartsWith('_'):
				// create the new member reference and set it up
				mre = MemberReferenceExpression(node.LexicalInfo)
				mre.Name = node.Name[1:]
				mre.Target = _inst.CloneNode()

				// replace the original reference in the AST
				// with the new member-reference
				node.ParentNode.Replace(node, mre)

	override def Expand(macro as MacroStatement) as Statement:
		assert 1 == macro.Arguments.Count
		assert macro.Arguments[0] isa ReferenceExpression

		inst = macro.Arguments[0] as ReferenceExpression

		// convert all _<ref> to inst.<ref>
		block = macro.Block
		ne = NameExpander(inst)
		ne.Visit(block)
		return block


Fill in more icon types.

Fill in more icon types.

namespace UnityScript.MonoDevelop.Completion

import System.Collections.Generic

import UnityScript
import UnityScript.MonoDevelop
import UnityScript.MonoDevelop.ProjectModel

import MonoDevelop.Core
import MonoDevelop.Projects
import MonoDevelop.Projects.Dom.Parser
import MonoDevelop.Ide.Gui
import MonoDevelop.Ide.Gui.Content
import MonoDevelop.Ide.CodeCompletion

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

class UnityScriptEditorCompletion(CompletionTextEditorExtension):

	_dom as ProjectDom
	_resolver as UnityScriptTypeResolver
	_project as DotNetProject

	override def Initialize():
		super()
		_dom = ProjectDomService.GetProjectDom(Document.Project) or ProjectDomService.GetFileDom(Document.FileName)
		InstallUnityScriptSyntaxModeIfNeeded()
		_resolver = UnityScriptTypeResolver()
		_project = Document.Project as DotNetProject
		InitializeProjectReferences()

	def InitializeProjectReferences():
		if _project is null:
			return

		for reference in _project.References:
			if ReferenceType.Project != reference.ReferenceType:
				_resolver.AddReference(reference.Reference)

	def InstallUnityScriptSyntaxModeIfNeeded():
		view = Document.GetContent[of MonoDevelop.SourceEditor.SourceEditorView]()
		return if view is null

		mimeType = UnityScriptParser.MimeType
		return if view.Document.SyntaxMode.MimeType == mimeType

		mode = Mono.TextEditor.Highlighting.SyntaxModeService.GetSyntaxMode(mimeType)
		if mode is not null:
			view.Document.SyntaxMode = mode
		else:
			LoggingService.LogWarning(GetType() + " could not get SyntaxMode for mimetype '" + mimeType + "'.")

	override def ExtendsEditor(doc as MonoDevelop.Ide.Gui.Document, editor as IEditableTextBuffer):
		return IsUnityScriptFile(doc.Name)

	override def HandleCodeCompletion(context as CodeCompletionContext, completionChar as char):
#		print "HandleCodeCompletion(${context.ToString()}, ${completionChar.ToString()})"

		match completionChar.ToString():
			case ' ':
				lineText = GetLineText(context.TriggerLine).TrimStart()
				if not lineText.StartsWith("import "):
					return null

				return ImportCompletionDataFor('')

			case '.':
				lineText = GetLineText(context.TriggerLine)
				lineLength = lineText.Length
				lineText = lineText.TrimStart()
				trimmedLength = lineLength - lineText.Length
				if lineText.StartsWith("import "):
					nameSpace = lineText[len("import "):context.TriggerLineOffset-(2+trimmedLength)].Trim()
					return ImportCompletionDataFor(nameSpace)

				result = null as CompletionDataList
				text = string.Format ("{0}{1} {2}", Document.TextEditor.GetText (0, context.TriggerOffset),
				                                    CompletionFinder.CompletionToken,
				                                    Document.TextEditor.GetText (context.TriggerOffset, Document.TextEditor.TextLength))
				# print text
				_resolver.Input.Clear()
				_resolver.Input.Add(StringInput("completion text", text))

				result = CompletionDataList()

				_resolver.ResolveAnd() do (type as IType):
					resultHash = Dictionary[of string,string]()
					for member in type.GetMembers():
						# print member
						resultHash[member.Name] = GetIconForMember(member)
					for pair in resultHash:
						result.Add(pair.Key, pair.Value)

				return result

			otherwise:
				return null

	def ImportCompletionDataFor(nameSpace as string):
#		print "ImportCompletionDataFor(${nameSpace})"

		result = CompletionDataList()
		for member in _dom.GetNamespaceContents(nameSpace, true, true):
			result.Add(member.Name, member.StockIcon)
		return result

	def GetLineText(line as int):
		return Document.TextEditor.GetLineText(line)

	def GetIconForMember(member as IEntity):
		match member.EntityType:
			case EntityType.BuiltinFunction:
				return Stock.Method
			case EntityType.Constructor:
				return Stock.Method
			case EntityType.Method:
				return Stock.Method
			case EntityType.Local:
				return Stock.Field
			case EntityType.Field:
				return Stock.Field
			case EntityType.Property:
				return Stock.Property
			case EntityType.Event:
				return Stock.Event
			otherwise:
				return Stock.Literal

namespace UnityScript.MonoDevelop.Completion

import System.Collections.Generic

import UnityScript
import UnityScript.MonoDevelop
import UnityScript.MonoDevelop.ProjectModel

import MonoDevelop.Core
import MonoDevelop.Projects
import MonoDevelop.Projects.Dom.Parser
import MonoDevelop.Ide.Gui
import MonoDevelop.Ide.Gui.Content
import MonoDevelop.Ide.CodeCompletion

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

class UnityScriptEditorCompletion(CompletionTextEditorExtension):

	_dom as ProjectDom
	_resolver as UnityScriptTypeResolver
	_project as DotNetProject

	override def Initialize():
		super()
		_dom = ProjectDomService.GetProjectDom(Document.Project) or ProjectDomService.GetFileDom(Document.FileName)
		InstallUnityScriptSyntaxModeIfNeeded()
		_resolver = UnityScriptTypeResolver()
		_project = Document.Project as DotNetProject
		InitializeProjectReferences()

	def InitializeProjectReferences():
		if _project is null:
			return

		for reference in _project.References:
			if ReferenceType.Project != reference.ReferenceType:
				_resolver.AddReference(reference.Reference)

	def InstallUnityScriptSyntaxModeIfNeeded():
		view = Document.GetContent[of MonoDevelop.SourceEditor.SourceEditorView]()
		return if view is null

		mimeType = UnityScriptParser.MimeType
		return if view.Document.SyntaxMode.MimeType == mimeType

		mode = Mono.TextEditor.Highlighting.SyntaxModeService.GetSyntaxMode(mimeType)
		if mode is not null:
			view.Document.SyntaxMode = mode
		else:
			LoggingService.LogWarning(GetType() + " could not get SyntaxMode for mimetype '" + mimeType + "'.")

	override def ExtendsEditor(doc as MonoDevelop.Ide.Gui.Document, editor as IEditableTextBuffer):
		return IsUnityScriptFile(doc.Name)

	override def HandleCodeCompletion(context as CodeCompletionContext, completionChar as char):
#		print "HandleCodeCompletion(${context.ToString()}, ${completionChar.ToString()})"

		match completionChar.ToString():
			case ' ':
				lineText = GetLineText(context.TriggerLine).TrimStart()
				if not lineText.StartsWith("import "):
					return null

				return ImportCompletionDataFor('')

			case '.':
				lineText = GetLineText(context.TriggerLine)
				lineLength = lineText.Length
				lineText = lineText.TrimStart()
				trimmedLength = lineLength - lineText.Length
				if lineText.StartsWith("import "):
					nameSpace = lineText[len("import "):context.TriggerLineOffset-(2+trimmedLength)].Trim()
					return ImportCompletionDataFor(nameSpace)

				result = null as CompletionDataList
				text = string.Format ("{0}{1} {2}", Document.TextEditor.GetText (0, context.TriggerOffset),
				                                    CompletionFinder.CompletionToken,
				                                    Document.TextEditor.GetText (context.TriggerOffset, Document.TextEditor.TextLength))
				# print text
				_resolver.Input.Clear()
				_resolver.Input.Add(StringInput("completion text", text))

				result = CompletionDataList()

				_resolver.ResolveAnd() do (type as IType):
					resultHash = Dictionary[of string,string]()
					for member in type.GetMembers():
						# print member
						resultHash[member.Name] = GetIconForMember(member)
					for pair in resultHash:
						result.Add(pair.Key, pair.Value)

				return result

			otherwise:
				return null

	def ImportCompletionDataFor(nameSpace as string):
#		print "ImportCompletionDataFor(${nameSpace})"

		result = CompletionDataList()
		for member in _dom.GetNamespaceContents(nameSpace, true, true):
			result.Add(member.Name, member.StockIcon)
		return result

	def GetLineText(line as int):
		return Document.TextEditor.GetLineText(line)

	def GetIconForMember(member as IEntity):
		match member.EntityType:
			case EntityType.Method:
				return Stock.Method
			case EntityType.Field:
				return Stock.Field
			case EntityType.Property:
				return Stock.Property
			case EntityType.Event:
				return Stock.Event
			otherwise:
				return Stock.Literal


an interactive calculator is better

an interactive calculator is better

namespace pegs

import Boo.Pegs

def push(ctx as PegContextWithPayload[of List], value as int):
	ctx.Payload.Push(value)

def pop(ctx as PegContextWithPayload[of List]) as int:
	return ctx.Payload.Pop()

peg:
	evaluate = spacing, addition, eof
	addition = term, --("+", spacing, term, { $push($pop + $pop) })
	term = factor, --("*", spacing, factor, { $push($pop * $pop) })
	factor = ++digit(), { $push(int.Parse($text)) }, spacing
	spacing = --whitespace()
	eof = not any()

while true:
	expression = prompt("> ")
	if string.IsNullOrEmpty(expression): break
	ctx = PegContextWithPayload[of List](expression, [])
	if evaluate.Eval(ctx):
		print pop(ctx)
	else:
		print "DOES NOT COMPUTE!"

namespace pegs

import Boo.Pegs

def push(ctx as PegContextWithPayload[of List], value as int):
	ctx.Payload.Push(value)

def pop(ctx as PegContextWithPayload[of List]) as int:
	return ctx.Payload.Pop()

peg:
	evaluate = spacing, addition, eof
	addition = term, --("+", term, { $push($pop + $pop) })
	term = factor, --("*", factor, { $push($pop * $pop) })
	factor = ++digit(), { $push(int.Parse($text)) }, spacing
	spacing = --whitespace()
	eof = not any()

ctx = PegContextWithPayload[of List]("3+2*4", [])
print evaluate.Eval(ctx)
print pop(ctx)


Update build script

Update build script

project_name = "FluentValidation"
solution_file = "FluentValidation.sln"
solution_file_silverlight = "FluentValidation.Silverlight.sln"
project_configuration = "release"
build_dir = "build"
test_assemblies = "src/FluentValidation.Tests/bin/${project_configuration}/FluentValidation.Tests.dll"
build_silverlight = false
ncover_path = "C:/Program Files (x86)/ncover"

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

target ci, (init, silverlight, compile, coverage, package):
  pass

target init:
  rm(build_dir)
  rm("teamcity-info.xml")

desc "Enables silverlight build"
target silverlight:
  print "Silverlight build enabled"
  build_silverlight = true

desc "Compiles solution"
target compile:
  msbuild(file: solution_file, configuration: project_configuration)

  if build_silverlight:
    msbuild(file: solution_file_silverlight, configuration: project_configuration)

desc "Runs tests"
target test:
  nunit(assembly: test_assemblies)

desc "Creates release package"
target deploy:
  #main binaries
  with FileList("src/FluentValidation/bin/${project_configuration}"):
    .Include("**/*")
    .ForEach def(file):
      file.CopyToDirectory("${build_dir}/${project_configuration}/FluentValidation")

  #Mvc integration
  with FileList("src/FluentValidation.Mvc/bin/${project_configuration}"):
    .Include("FluentValidation.Mvc.*")
    .ForEach def(file):
      file.CopyToDirectory("${build_dir}/${project_configuration}/MVC")

  #xVal
  with FileList("src/FluentValidation.xValIntegration/bin/${project_configuration}"):
    .Include("FluentValidation.xValIntegration.*")
    .Include("xVal.dll")
    .ForEach def(file):
      file.CopyToDirectory("${build_dir}/${project_configuration}/Experimental/xVal")

  #silverlight
  if build_silverlight:
    with FileList("src/FluentValidation.Silverlight/bin/${project_configuration}"):
      .Include("*.{dll,pdb,xml}")
      .ForEach def(file):
        file.CopyToDirectory("${build_dir}/${project_configuration}/Experimental/Silverlight")

  #License/Changelog
  with FileList():
    .Include("License.txt")
    .Include("Changelog.txt")
    .ForEach def(file):
      file.CopyToDirectory("${build_dir}/${project_configuration}")

target package, (deploy):
  zip("${build_dir}/${project_configuration}", "${build_dir}/FluentValidation.zip")

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

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

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

project_name = "FluentValidation"
solution_file = "FluentValidation.sln"
solution_file_silverlight = "FluentValidation.Silverlight.sln"
project_configuration = "release"
build_dir = "build"
test_assemblies = "src/FluentValidation.Tests/bin/${project_configuration}/FluentValidation.Tests.dll"
build_silverlight = false
ncover_path = "C:/Program Files (x86)/ncover"

target default, (init, compile, test, deploy):
  pass

target ci, (init, silverlight, compile, coverage, package):
  pass

target init:
  rm(build_dir)
  rm("teamcity-info.xml")

desc "Enables silverlight build"
target silverlight:
  print "Silverlight build enabled"
  build_silverlight = true

desc "Compiles solution"
target compile:
  msbuild(file: solution_file, configuration: project_configuration)

  if build_silverlight:
    msbuild(file: solution_file_silverlight, configuration: project_configuration)

desc "Runs tests"
target test:
  nunit(assembly: test_assemblies)

desc "Creates release package"
target deploy:
  #main binaries
  with FileList("src/FluentValidation/bin/${project_configuration}"):
    .Include("**/*")
    .ForEach def(file):
      file.CopyToDirectory("${build_dir}/${project_configuration}/FluentValidation")

  #Mvc integration
  with FileList("src/FluentValidation.Mvc/bin/${project_configuration}"):
    .Include("FluentValidation.Mvc.*")
    .ForEach def(file):
      file.CopyToDirectory("${build_dir}/${project_configuration}/MVC")

  #xVal
  with FileList("src/FluentValidation.xValIntegration/bin/${project_configuration}"):
    .Include("FluentValidation.xValIntegration.*")
    .Include("xVal.dll")
    .ForEach def(file):
      file.CopyToDirectory("${build_dir}/${project_configuration}/xVal")

  #silverlight
  if build_silverlight:
    with FileList("src/FluentValidation.Silverlight/bin/${project_configuration}"):
      .Include("*.{dll,pdb,xml}")
      .ForEach def(file):
        file.CopyToDirectory("${build_dir}/${project_configuration}/Silverlight")

  #License/Changelog
  with FileList():
    .Include("License.txt")
    .Include("Changelog.txt")
    .ForEach def(file):
      file.CopyToDirectory("${build_dir}/${project_configuration}")

target package, (deploy):
  zip("${build_dir}/${project_configuration}", "${build_dir}/FluentValidation.zip")

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

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

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


little update to suport non primitive type names

namespace Boojay.Compilation.TypeSystem

import Boo.Lang.Compiler
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.TypeSystem.Services
import Boo.Lang.PatternMatching

class JarMethod(IMethod):

	_declaringType as IType
	_name as string
	_descriptor as string
	_access as int

	def constructor(declaringType as IType, name as string, descriptor as string, access as int):
		_declaringType = declaringType
		_name = name
		_descriptor = descriptor
		_access = access

	EntityType:
		get: return EntityType.Method

	Name:
		get: return _name

	FullName:
		get: return "${_declaringType.FullName}.${_name}"

	DeclaringType:
		get: return _declaringType

	IsPublic:
		get: return (_access & org.objectweb.asm.Opcodes.ACC_PUBLIC) != 0

	IsProtected:
		get: return (_access & org.objectweb.asm.Opcodes.ACC_PROTECTED) != 0

	IsStatic:
		get: return (_access & org.objectweb.asm.Opcodes.ACC_STATIC) != 0

	AcceptVarArgs:
		get: return (_access & org.objectweb.asm.Opcodes.ACC_VARARGS) != 0

	IsExtension:
		get: return false // FIXME

	Type:
		get: return self.CallableType

	CallableType:
		get: return my(TypeSystemServices).GetCallableType(self)

	ReturnType as IType:
		get:
			asmType = org.objectweb.asm.Type.getReturnType(_descriptor)
			return ResolveTypeName(asmType)

	private def ResolveTypeName(asmType as org.objectweb.asm.Type):
		asmTypeName = asmType.ToString()
		match asmTypeName:
			case "b": return my(TypeSystemServices).ByteType
			otherwise: return ResolveNonPrimitive(asmTypeName)

	private def ResolveNonPrimitive(typeName as string):
		if typeName[0] == "L":
			booTypeName = typeName[1:].Replace("/", ".")
			return my(NameResolutionService).ResolveQualifiedName(booTypeName)
		raise "Unknown NonPrimitive ${typeName}"

	def GetParameters(): // FIXME
		return array[of IParameter](0)

namespace Boojay.Compilation.TypeSystem

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

class JarMethod(IMethod):

	_declaringType as IType
	_name as string
	_descriptor as string
	_access as int

	def constructor(declaringType as IType, name as string, descriptor as string, access as int):
		_declaringType = declaringType
		_name = name
		_descriptor = descriptor
		_access = access

	EntityType:
		get: return EntityType.Method

	Name:
		get: return _name

	FullName:
		get: return "${_declaringType.FullName}.${_name}"

	DeclaringType:
		get: return _declaringType

	IsPublic:
		get: return (_access & org.objectweb.asm.Opcodes.ACC_PUBLIC) != 0

	IsProtected:
		get: return (_access & org.objectweb.asm.Opcodes.ACC_PROTECTED) != 0

	IsStatic:
		get: return (_access & org.objectweb.asm.Opcodes.ACC_STATIC) != 0

	AcceptVarArgs:
		get: return (_access & org.objectweb.asm.Opcodes.ACC_VARARGS) != 0

	IsExtension:
		get: return false // FIXME

	Type:
		get: return self.CallableType

	CallableType:
		get: return my(TypeSystemServices).GetCallableType(self)

	ReturnType as IType: // FIXME
		get:
			print "RETURNTYPE:", org.objectweb.asm.Type.getReturnType(_descriptor)
			return null // return my(NameResolutionService).ResolveQualifiedName()

	def GetParameters(): // FIXME
		return array[of IParameter](0)


make Extensions class static so it can be more easily converted to actionscript

namespace UnityScript.Lang

static class Extensions:

	[Extension]
	def op_Equality(lhs as System.Char, rhs as System.String):
		return 1 == len(rhs) and lhs == rhs[0]

	[Extension]
	def op_Equality(lhs as System.String, rhs as System.Char):
		return rhs == lhs

	[Extension]
	def op_Inequality(lhs as System.Char, rhs as System.String):
		return 1 != len(rhs) or lhs != rhs[0]

	[Extension]
	def op_Inequality(lhs as System.String, rhs as System.Char):
		return rhs != lhs

	[Extension]
	length[a as System.Array]:
		get: return a.Length

	[Extension]
	length[s as string]:
		get: return s.Length

	[Extension]
	def op_Implicit(e as System.Enum) as bool:
		return (e cast System.IConvertible).ToInt32(null) != 0

namespace UnityScript.Lang

class Extensions:

	[Extension]
	static def op_Equality(lhs as System.Char, rhs as System.String):
		return 1 == len(rhs) and lhs == rhs[0]

	[Extension]
	static def op_Equality(lhs as System.String, rhs as System.Char):
		return rhs == lhs

	[Extension]
	static def op_Inequality(lhs as System.Char, rhs as System.String):
		return 1 != len(rhs) or lhs != rhs[0]

	[Extension]
	static def op_Inequality(lhs as System.String, rhs as System.Char):
		return rhs != lhs

	[Extension]
	static length[a as System.Array]:
		get:
			return a.Length

	[Extension]
	static length[s as string]:
		get:
			return s.Length

	[Extension]
	static def op_Implicit(e as System.Enum) as bool:
		return cast(System.IConvertible, e).ToInt32(null) != 0


sort suggested members on autocompletion

git-svn-id: fcce7d6ce0ac15bf24f68871b5145d46fc068279@2858 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.Lang.Interpreter

import System
import System.Collections
import System.Collections.Generic
import System.IO
import System.Text
import System.Text.RegularExpressions
import Boo.Lang
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.IO

class InteractiveInterpreter2(AbstractInterpreter):

	_values = {}

	_declarations = {}

	_representers = []

	[property(ShowWarnings)]
	_showWarnings = false

	[property(BlockStarters, value is not null)]
	_blockStarters = (char(':'), char('\\'),)

	[getter(LastValue)]
	_lastValue

	[property(Print, value is not null)]
	_print as callable(object) = print

	_entityNameComparer = EntityNameComparer()

	def constructor():
		super()
		_disableColors = true if Environment.GetEnvironmentVariable("BOOISH_NOCOLORS") is not null
		InitializeStandardReferences()
		LoadHistory()

	def constructor(parser as ICompilerStep):
		super(parser)
		_disableColors = true if Environment.GetEnvironmentVariable("BOOISH_NOCOLORS") is not null
		InitializeStandardReferences()
		LoadHistory()

	def Reset():
		_values.Clear()
		_declarations.Clear()
		_lastValue = null
		_indent = 0
		InitializeStandardReferences()

	public final static HISTORY_FILENAME = "booish_history"
	public final static HISTORY_CAPACITY = 100
	protected _history = System.Collections.Generic.Queue of string(HISTORY_CAPACITY)
	protected _historyFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), HISTORY_FILENAME)
	protected _historyIndex = 0
	protected _session = System.Collections.Generic.List of string()

	private _buffer = StringBuilder()	#buffer to be executed
	private _line = StringBuilder()		#line being edited

	CurrentPrompt as string:
		get:
			if _indent > 0:
				return BlockPrompt
			return DefaultPrompt

	[property(DefaultPrompt)]
	_defaultPrompt = ">>>"

	[property(BlockPrompt)]
	_blockPrompt = "..."

	[property(DisableColors)]
	_disableColors = false

	[property(InterpreterColor)] # messages from the interpreter (not from user code)
	_interpreterColor = ConsoleColor.Gray

	[property(PromptColor)]
	_promptColor = ConsoleColor.Green

	[property(ExceptionColor)]
	_exceptionColor = ConsoleColor.Red

	[property(SuggestionsColor)]
	_suggestionsColor = ConsoleColor.Yellow

	[property(SelectedSuggestionColor)]
	_selectedSuggestionColor = ConsoleColor.Magenta

	[property(SelectedSuggestionIndex)]
	_selectedSuggestionIndex = -1

	[property(Suggestions)]
	_suggestions as (object)

	CanAutoComplete as bool:
		get:
			return _selectedSuggestionIndex >= 0 and _suggestions is not null

	private _builtins as (IEntity)
	private _filter as string

	private def ConsolePrintPrompt():
		Console.ForegroundColor = _promptColor if not _disableColors
		Console.Write(CurrentPrompt)
		#TODO: automatic indentation option ?
		#for i in range(_indent):
		#	_line.Append("\t")
		#	Console.Write("\t")
		Console.ResetColor() if not _disableColors

	private def ConsolePrintMessage(msg as string):
		Console.ForegroundColor = _interpreterColor if not _disableColors
		print msg
		Console.ResetColor() if not _disableColors

	private def ConsolePrintException(e as Exception):
		Console.ForegroundColor = _exceptionColor if not _disableColors
		print e
		Console.ResetColor() if not _disableColors

	private def ConsolePrintError(msg as string):
		Console.ForegroundColor = _exceptionColor if not _disableColors
		print msg
		Console.ResetColor() if not _disableColors

	protected def ConsolePrintSuggestions():
		cursorLeft = Console.CursorLeft
		#cursorTop = Console.CursorTop
		Console.Write(Environment.NewLine)

		i = 0

		Array.Sort(_suggestions) if _suggestions isa (string)
		Array.Sort[of IEntity](_suggestions, _entityNameComparer) if _suggestions isa (IEntity)

		for s in _suggestions as (object):
			Console.ForegroundColor = _suggestionsColor if not _disableColors
			Console.Write(", ") if i > 0
			if i > 20: #TODO: maxcandidates pref + paging?
				Console.Write("... (too much candidates)")
				break
			if i == _selectedSuggestionIndex:
				Console.ForegroundColor = _selectedSuggestionColor if not _disableColors
			if s isa IEntity:
				Console.Write(DescribeEntity(s as IEntity))
			else:
				Console.Write(s)
			i++

		Console.ResetColor() if not _disableColors
		#Console.CursorTop = cursorTop
		Console.Write(Environment.NewLine)
		ConsolePrintPrompt()
		Console.Write(_line.ToString())
		Console.CursorLeft = cursorLeft

	private static re_open = Regex("\\(", RegexOptions.Singleline)
	private static re_close = Regex("\\)", RegexOptions.Singleline)

	def DisplaySuggestions(query as string):
		#TODO: FIXME: refactor to one regex?
		p_open = re_open.Matches(query).Count
		p_close = re_close.Matches(query).Count
		if p_open > p_close:
			query = query.Split(" ,(\t".ToCharArray(), 100)[-1]
		else:
			query = query.Split(" ,\t".ToCharArray(), 100)[-1]
		if query.LastIndexOf('.') > 0:
			codeToComplete = query[0:query.LastIndexOf('.')+1]
			_suggestions = SuggestCodeCompletion(codeToComplete+"__codecomplete__")
			_filter = query[query.LastIndexOf('.')+1:]
			_suggestions = array(e for e in _suggestions as (IEntity)
								unless not e.Name.StartsWith(_filter)) as (IEntity)

		if not _suggestions or 0 == len(_suggestions): #suggest a  var
			_filter = query
			_suggestions = array(var.ToString() for var in _values.Keys
									unless not var.ToString().StartsWith(_filter))

		if not _suggestions or 0 == len(_suggestions):
			_selectedSuggestionIndex = -1
			#Console.Beep() #TODO: flash background?
		elif 1 == len(_suggestions):
			AutoComplete()
		else:
			ConsolePrintSuggestions()

	def AutoComplete():
		if not _suggestions:
			raise InvalidOperationException("no suggestions")

		s = _suggestions[_selectedSuggestionIndex] as IEntity
		if s:
			if s.EntityType == EntityType.Method:
				m = s as IMethod
				completion = s.Name[len(_filter):]
				Console.Write(completion) #FIXME: insert at cursor!
				_line.Append(completion)
				if not m.GetParameters() or m.GetParameters().Length == 0:
					Console.Write('()') #FIXME: insert at cursor!
					_line.Append('()')
				else:
					Console.Write('(') #FIXME: insert at cursor!
					_line.Append('(')

			else: # not a Method
				completion = s.Name[len(_filter):]
				Console.Write(completion) #FIXME: insert at cursor!
				_line.Append(completion)
		else:
			completion = (_suggestions[_selectedSuggestionIndex] as string)[len(_filter):]
			Console.Write(completion) #FIXME: insert at cursor!
			_line.Append(completion)

		_selectedSuggestionIndex = -1
		_suggestions = null

	private _beforeHistory = string.Empty

	def DisplayHistory():
		if _history.Count == 0 or _historyIndex < 0 or _historyIndex > _history.Count:
			return
		Console.CursorLeft = len(CurrentPrompt)
		Console.Write(string.Empty.PadLeft(_line.Length, char(' ')))
		line = _history.ToArray()[_historyIndex]
		_line.Length = 0
		_line.Append(line)
		Console.CursorLeft = len(CurrentPrompt)
		Console.Write(line)

	def ConsoleLoopEval():
		Console.CursorVisible = true
		ConsolePrintPrompt()

		lastChar = char('0')
		key = ConsoleKey.LeftArrow
		while not _quit:
			cki = Console.ReadKey(true) #TODO: fix mono different behavior when ()
			key = cki.Key
			keyChar = cki.KeyChar
			control = false

			newLine = keyChar in Environment.NewLine

			if char.IsControl(keyChar):
				control = true
				if keyChar == char('\t'):
					test = char(' ')
					test = _line.ToString()[_line.Length-1] if _line.Length > 0
					if char.IsLetterOrDigit(test) or test == char('.'):
						_selectedSuggestionIndex = 0
						DisplaySuggestions(_line.ToString())
					else:
						_line.Append("    ") #TODO: _tabWidth pref
						Console.Write("    ")

				#line-editing support
				if key == ConsoleKey.Backspace:
					if Console.CursorLeft > len(CurrentPrompt) and _line.Length > 0:
						cx = Console.CursorLeft-len(CurrentPrompt)-1
						_line.Remove(cx, 1)
						cx2 = --Console.CursorLeft
						Console.Write("${_line.ToString(cx, _line.Length-cx)} ")
						Console.CursorLeft = cx2
				elif key == ConsoleKey.Delete:
					if Console.CursorLeft >= len(CurrentPrompt) and _line.Length > 0:
						cx = Console.CursorLeft-len(CurrentPrompt)
						if cx < _line.Length:
							_line.Remove(cx, 1)
							cx2 = Console.CursorLeft
							Console.Write("${_line.ToString(cx, _line.Length-cx)} ")
							Console.CursorLeft = cx2
				elif key == ConsoleKey.LeftArrow:
					if Console.CursorLeft > len(CurrentPrompt) and _line.Length > 0:
						Console.CursorLeft--
				elif key == ConsoleKey.RightArrow:
					if Console.CursorLeft < (len(CurrentPrompt)+_line.Length):
						Console.CursorLeft++
				elif key == ConsoleKey.Home:
					Console.CursorLeft = len(CurrentPrompt)
				elif key == ConsoleKey.End:
					Console.CursorLeft = len(CurrentPrompt) + _line.Length

				#history support
				if key == ConsoleKey.UpArrow:
					if _historyIndex > 0:
						_historyIndex--
						DisplayHistory()
				if key == ConsoleKey.DownArrow:
					if _historyIndex < _history.Count-1:
						_historyIndex++
						DisplayHistory()

				#auto-completion support
				if CanAutoComplete:
					if key == ConsoleKey.LeftArrow:
						if _selectedSuggestionIndex > 0:
							_selectedSuggestionIndex--
						else:
							_selectedSuggestionIndex = len(_suggestions)
						DisplaySuggestions(_line.ToString())
					if key == ConsoleKey.RightArrow:
						if _selectedSuggestionIndex+1 < len(_suggestions):
							_selectedSuggestionIndex++
						else:
							_selectedSuggestionIndex = 0
						DisplaySuggestions(_line.ToString())
					if newLine:
						AutoComplete()
						continue
				if not newLine:
					continue

			_selectedSuggestionIndex = -1

			cx = Console.CursorLeft-len(CurrentPrompt)
			line = _line.ToString()

			if not newLine:
				if cx < len(line):	#line-editing support
					_line.Insert(cx, keyChar) if not control
					Console.Write(_line.ToString(cx, _line.Length-cx))
					Console.CursorLeft = len(CurrentPrompt)+cx+1
				else:
					_line.Append(keyChar) if not control
					Console.Write(keyChar)

			line = _line.ToString()

			if newLine:
				Console.Write(Environment.NewLine)

				if not TryRunCommand(line):
					_buffer.Append(line)
					_buffer.Append(Environment.NewLine)
					AddToHistory(line)

					try:
						if len(line) > 0:
							_indent++ if line[len(line)-1] in _blockStarters
							_indent-- if line[len(line)-1] == keyChar and _indent > 0
						else:
							_indent--
						if _indent == 0:
							InternalLoopEval(_buffer.ToString())
							_buffer.Length = 0
					except x as System.Reflection.TargetInvocationException:
						ConsolePrintException(x.InnerException)
					except x:
						ConsolePrintException(x)

					_line.Length = 0
					ConsolePrintPrompt()

			lastChar = keyChar

		SaveHistory()
		DisplayGoodbye()

	/* returns false if no command has been processed, true otherwise */
	def TryRunCommand(line as string):
		if not line.StartsWith("/"):
			return false

		cmd = line.Split()

		if len(cmd) == 1:
			if cmd[0] == "/q" or cmd[0] == "/quit":
				quit()
			elif cmd[0] == "/?" or cmd[0] == "/h" or cmd[0] == "/help":
				DisplayHelp()
				_selectedSuggestionIndex = -1
				_buffer.Length = 0
				ConsolePrintPrompt()
			elif cmd[0] == "/g" or cmd[0] == "/globals":
				globals()
			else:
				return false

		elif len(cmd) == 2:
			if cmd[0] == "/l" or cmd[0] == "/load":
				load(cmd[1])
				_line.Length = 0
				ConsolePrintPrompt()
			elif cmd[0] == "/s" or cmd[0] == "/save":
				save(cmd[1])
				_line.Length = 0
				ConsolePrintPrompt()
			else:
				return false

		else:
			return false
		return true

	private _indent as int = 0

	def LoopEval(code as string):
		using console = ConsoleCapture():
			result = InternalLoopEval(code)
			for line in System.IO.StringReader(console.ToString()):
				_print(line)
		return result

	private def InternalLoopEval(code as string):
		result = self.Eval(code)
		if ShowWarnings:
			self.DisplayProblems(result.Warnings)
		if not self.DisplayProblems(result.Errors):
			ProcessLastValue()
			_session.Add(code)
		return result

	private def ProcessLastValue():
		_ = self.LastValue
		if _ is not null:
			_print(repr(_))
			SetValue("_", _)

	override def Declare([required] name as string,
				[required] type as System.Type):
		_declarations.Add(name, type)

	override def SetLastValue(value):
		_lastValue = value

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

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

	override def Lookup([required] name as string):
		type as System.Type = _declarations[name]
		return type if type is not null

		value = GetValue(name)
		return value.GetType() if value is not null

	def DisplayProblems(problems as ICollection):
		return if problems is null or problems.Count == 0
		Console.ForegroundColor = _exceptionColor if not _disableColors
		for problem as duck in problems:
			markLocation(problem.LexicalInfo)
			type = ("WARNING", "ERROR")[problem isa CompilerError]
			_print("${type}: ${problem.Message}")
		Console.ResetColor() if not _disableColors
		if problems.Count > 0:
			return true
		return false

	private def markLocation(location as LexicalInfo):
		pos = location.Column
		_print("---" + "-" * pos + "^") if pos > 0

	private def InitializeStandardReferences():
		SetValue("interpreter", self)
		SetValue("dir", dir)
		SetValue("help", help)
		SetValue("print", { value | _print(value) })
		SetValue("load", load)
		SetValue("globals", globals)
		SetValue("getRootNamespace", Namespace.GetRootNamespace)

	def DisplayHelp():
		Console.ForegroundColor = _interpreterColor	if not _disableColors
		print """Welcome to booish, an interpreter for the boo programming language.
Running boo ${BooVersion} in CLR v${Environment.Version}.

The following builtin functions are available:
    /d[ir] type : lists the members of a type
    /h[elp] type : prints detailed information about a type
    /l[oad] file : evals an external boo file
    /s[ave] file : writes your current booish session into file
    /g[lobals] : returns names of all variables known to interpreter
    /n[ames] : namespace navigation
    /q[uit] : exits the interpreter

Enter boo code in the prompt below."""
		Console.ResetColor() if not _disableColors

	def DisplayGoodbye():	// booish is friendly
		Console.ForegroundColor = _interpreterColor if not _disableColors
		print ""
		print "All your boo are belong to us!"
		Console.ResetColor() if not _disableColors

	def LoadHistory():
		try:
			using history = File.OpenText(_historyFile):
				while line = history.ReadLine():
					AddToHistory(line)
		except:
			ConsolePrintError("Cannot load history from '${_historyFile}'")

	def AddToHistory(line as string):
		return if 0 == (len(line) - len(Environment.NewLine))
		_history.Dequeue() if _history.Count >= HISTORY_CAPACITY
		line = line.Replace(Environment.NewLine, "")
		_history.Enqueue(line)
		_historyIndex = _history.Count

	def SaveHistory():
		try:
			using sw = System.IO.File.CreateText(_historyFile):
				for line in _history:
					sw.WriteLine(line)
		except:
			ConsolePrintError("Cannot save history to '${_historyFile}'.")

	def globals():
		return array(string, _values.Keys)

	def dir([required] obj):
		type = (obj as Type) or obj.GetType()
		return array(member for member in type.GetMembers()
						unless (method=(member as System.Reflection.MethodInfo))
							and method.IsSpecialName)

	def load([required] path as string):
		if path.EndsWith(".boo"):
			ConsolePrintMessage("Evaluating '${path}' ...")
			result = EvalCompilerInput(FileInput(path))
			if ShowWarnings:
				DisplayProblems(result.Warnings)
			if not DisplayProblems(result.Errors):
				ProcessLastValue()
		else:
			try:
				ConsolePrintMessage("Adding reference to '${path}'")
				References.Add(System.Reflection.Assembly.LoadFrom(path))
			except e:
				ConsolePrintError(e.Message)

	def save([required] path as string):
		if path is string.Empty:
			path = "booish_session.boo"
		elif not path.EndsWith(".boo"):
			path = "${path}.boo"
		try:
			using sw = System.IO.File.CreateText(path):
				for line in _session:
					sw.Write(line)
			ConsolePrintMessage("Session saved to '${path}'.")
		except:
			ConsolePrintError("Cannot save to '${path}'. Check if path is valid and has correct permissions.")

	def help(obj):
		type = (obj as Type) or obj.GetType()
		DescribeType("    ", type)

	private _quit = false
	def quit():
		_quit = true

	def DescribeType(indent as string, type as Type):
		if type.IsInterface:
			typeDef = "interface"
			baseTypes = array(GetBooTypeName(t) for t in type.GetInterfaces())
		else:
			typeDef = "class"
			baseTypes = (GetBooTypeName(type.BaseType),) + array(GetBooTypeName(t) for t in type.GetInterfaces())

		_print("${typeDef} ${type.Name}(${join(baseTypes, ', ')}):")
		_print("")

		for ctor in type.GetConstructors():
			_print("${indent}def constructor(${DescribeParameters(ctor.GetParameters())})")
			_print("")

		sortByName = def (lhs as Reflection.MemberInfo, rhs as Reflection.MemberInfo):
			return lhs.Name.CompareTo(rhs.Name)

		for f as Reflection.FieldInfo in List(type.GetFields()).Sort(sortByName):
			_print("${indent}public ${DescribeField(f)}")
			_print("")

		for p as Reflection.PropertyInfo in List(type.GetProperties()).Sort(sortByName):
			_print("${indent}${DescribeProperty(p)}:")
			_print("${indent}${indent}get") if p.GetGetMethod() is not null
			_print("${indent}${indent}set") if p.GetSetMethod() is not null
			_print("")

		for m as Reflection.MethodInfo in List(type.GetMethods()).Sort(sortByName):
			continue if m.IsSpecialName
			_print("${indent}${DescribeMethod(m)}")
			_print("")

		for e as Reflection.EventInfo in List(type.GetEvents()).Sort(sortByName):
			_print("${indent}${DescribeEvent(e)}")
			_print("")

	static def DescribeEntity(entity as IEntity):
		method = entity as ExternalMethod
		if method is not null:
			return InteractiveInterpreter.DescribeMethod(method.MethodInfo)
		field = entity as ExternalField
		if field is not null:
			return InteractiveInterpreter.DescribeField(field.FieldInfo)
		property = entity as ExternalProperty
		if property is not null:
			return InteractiveInterpreter.DescribeProperty(property.PropertyInfo)
		e = entity as ExternalEvent
		if e is not null:
			return InteractiveInterpreter.DescribeEvent(e.EventInfo)
		return entity.ToString()

	static def DescribeEvent(e as Reflection.EventInfo):
		return "${DescribeModifiers(e)}event ${e.Name} as ${e.EventHandlerType}"

	static def DescribeProperty(p as Reflection.PropertyInfo):
		modifiers = DescribeModifiers(p)
		params = DescribePropertyParameters(p.GetIndexParameters())
		return "${modifiers}${p.Name}${params} as ${GetBooTypeName(p.PropertyType)}"

	static def DescribeField(f as Reflection.FieldInfo):
		return "${DescribeModifiers(f)}${f.Name} as ${GetBooTypeName(f.FieldType)}"

	static def DescribeMethod(m as Reflection.MethodInfo):
		returnType = GetBooTypeName(m.ReturnType)
		modifiers = DescribeModifiers(m)
		return "${modifiers}def ${m.Name}(${DescribeParameters(m.GetParameters())}) as ${returnType}"

	static def DescribeModifiers(f as Reflection.FieldInfo):
		return "static " if f.IsStatic
		return ""

	static def DescribeModifiers(m as Reflection.MethodBase):
		return "static " if m.IsStatic
		return ""

	static def DescribeModifiers(e as Reflection.EventInfo):
		return DescribeModifiers(e.GetAddMethod(true) or e.GetRemoveMethod(true))

	static def DescribeModifiers(p as Reflection.PropertyInfo):
		accessor = p.GetGetMethod(true) or p.GetSetMethod(true)
		return DescribeModifiers(accessor)

	static def DescribePropertyParameters(parameters as (Reflection.ParameterInfo)):
		return "" if 0 == len(parameters)
		return "(${DescribeParameters(parameters)})"

	static def DescribeParameters(parameters as (Reflection.ParameterInfo)):
		return join(DescribeParameter(p) for p in parameters, ", ")

	static def DescribeParameter(p as Reflection.ParameterInfo):
		return "${p.Name} as ${GetBooTypeName(p.ParameterType)}"

	static def GetBooTypeName(type as System.Type) as string:
		return "(${GetBooTypeName(type.GetElementType())})" if type.IsArray
		return "object" if object is type
		return "string" if string is type
		return "void" if void is type
		return "bool" if bool is type
		return "byte" if byte is type
		return "char" if char is type
		return "sbyte" if sbyte is type
		return "short" if short is type
		return "ushort" if ushort is type
		return "int" if int is type
		return "uint" if uint is type
		return "long" if long is type
		return "ulong" if ulong is type
		return "single" if single is type
		return "double" if double is type
		return "date" if date is type
		return "timespan" if timespan is type
		return "regex" if regex is type
		return type.FullName

	def repr(value):
		writer = System.IO.StringWriter()
		repr(value, writer)
		return writer.ToString()

	def repr(value, writer as System.IO.TextWriter):
		return unless value is not null
		InitializeRepresenters() if 0 == len(_representers)
		GetBestRepresenter(value.GetType())(value, writer)

	private def InitializeRepresenters():
		AddRepresenter(string) do (value as string, writer as TextWriter):
			Visitors.BooPrinterVisitor.WriteStringLiteral(value, writer)

		AddRepresenter(bool) do (value as bool, writer as TextWriter):
			writer.Write(("false", "true")[value])

		AddRepresenter(Array) do (a as Array, writer as TextWriter):
			writer.Write("(")
			RepresentItems(a, writer)
			writer.Write(")")

		AddRepresenter(Delegate) do (d as Delegate, writer as TextWriter):
			method = d.Method
			writer.Write(method.DeclaringType.FullName)
			writer.Write(".")
			writer.Write(method.Name)

		AddRepresenter(IDictionary) do (value as IDictionary, writer as TextWriter):
			writer.Write("{")
			i = 0
			for key in value.Keys:
				writer.Write(", ") if i
				repr(key, writer)
				writer.Write(": ")
				repr(value[key], writer)
				++i
			writer.Write("}")

		AddRepresenter(IList) do (value as IList, writer as TextWriter):
			writer.Write("[")
			RepresentItems(value, writer)
			writer.Write("]")

		AddRepresenter(object) do (value, writer as TextWriter):
			writer.Write(value)

	private def RepresentItems(items, writer as TextWriter):
		i = 0
		for item in items:
			writer.Write(", ") if i > 0
			repr(item, writer)
			++i

	callable Representer(value, writer as TextWriter)

	private def AddRepresenter(type as Type, value as Representer):
		_representers.Add((type, value))

	def GetBestRepresenter(type as Type) as Representer:
		for key as Type, value in _representers:
			return value if key.IsAssignableFrom(type)
		assert false, "An appropriate representer could not be found!"

class EntityNameComparer(IComparer of IEntity):
	def Compare(a as IEntity, b as IEntity) as int:
		return string.Compare(a.Name, b.Name)

#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.Interpreter

import System
import System.Collections
import System.IO
import System.Text
import System.Text.RegularExpressions
import Boo.Lang
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.IO

class InteractiveInterpreter2(AbstractInterpreter):

	_values = {}

	_declarations = {}

	_representers = []

	[property(ShowWarnings)]
	_showWarnings = false

	[property(BlockStarters, value is not null)]
	_blockStarters = (char(':'), char('\\'),)

	[getter(LastValue)]
	_lastValue

	[property(Print, value is not null)]
	_print as callable(object) = print

	def constructor():
		super()
		_disableColors = true if Environment.GetEnvironmentVariable("BOOISH_NOCOLORS") is not null
		InitializeStandardReferences()
		LoadHistory()

	def constructor(parser as ICompilerStep):
		super(parser)
		_disableColors = true if Environment.GetEnvironmentVariable("BOOISH_NOCOLORS") is not null
		InitializeStandardReferences()
		LoadHistory()

	def Reset():
		_values.Clear()
		_declarations.Clear()
		_lastValue = null
		_indent = 0
		InitializeStandardReferences()

	public final static HISTORY_FILENAME = "booish_history"
	public final static HISTORY_CAPACITY = 100
	protected _history = System.Collections.Generic.Queue of string(HISTORY_CAPACITY)
	protected _historyFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), HISTORY_FILENAME)
	protected _historyIndex = 0
	protected _session = System.Collections.Generic.List of string()

	private _buffer = StringBuilder()	#buffer to be executed
	private _line = StringBuilder()		#line being edited

	CurrentPrompt as string:
		get:
			if _indent > 0:
				return BlockPrompt
			return DefaultPrompt

	[property(DefaultPrompt)]
	_defaultPrompt = ">>>"

	[property(BlockPrompt)]
	_blockPrompt = "..."

	[property(DisableColors)]
	_disableColors = false

	[property(InterpreterColor)] # messages from the interpreter (not from user code)
	_interpreterColor = ConsoleColor.Gray

	[property(PromptColor)]
	_promptColor = ConsoleColor.Green

	[property(ExceptionColor)]
	_exceptionColor = ConsoleColor.Red

	[property(SuggestionsColor)]
	_suggestionsColor = ConsoleColor.Yellow

	[property(SelectedSuggestionColor)]
	_selectedSuggestionColor = ConsoleColor.Magenta

	[property(SelectedSuggestionIndex)]
	_selectedSuggestionIndex = -1

	[property(Suggestions)]
	_suggestions as (object)

	CanAutoComplete as bool:
		get:
			return _selectedSuggestionIndex >= 0 and _suggestions is not null

	private _builtins as (IEntity)
	private _filter as string

	private def ConsolePrintPrompt():
		Console.ForegroundColor = _promptColor if not _disableColors
		Console.Write(CurrentPrompt)
		#TODO: automatic indentation option ?
		#for i in range(_indent):
		#	_line.Append("\t")
		#	Console.Write("\t")
		Console.ResetColor() if not _disableColors

	private def ConsolePrintMessage(msg as string):
		Console.ForegroundColor = _interpreterColor if not _disableColors
		print msg
		Console.ResetColor() if not _disableColors

	private def ConsolePrintException(e as Exception):
		Console.ForegroundColor = _exceptionColor if not _disableColors
		print e
		Console.ResetColor() if not _disableColors

	private def ConsolePrintError(msg as string):
		Console.ForegroundColor = _exceptionColor if not _disableColors
		print msg
		Console.ResetColor() if not _disableColors

	protected def ConsolePrintSuggestions():
		cursorLeft = Console.CursorLeft
		#cursorTop = Console.CursorTop
		Console.Write(Environment.NewLine)

		i = 0

		if _suggestions isa (string):
			for l in _suggestions as (string):
				Console.ForegroundColor = _suggestionsColor if not _disableColors
				Console.Write(", ") if i > 0
				if i > 20: #TODO: maxcandidates pref + paging?
					Console.Write("... (too much candidates)")
					break
				if i == _selectedSuggestionIndex:
					Console.ForegroundColor = _selectedSuggestionColor if not _disableColors
				Console.Write(l)
				i++

		elif _suggestions isa (IEntity):
			for e in _suggestions as (IEntity):
				Console.ForegroundColor = _suggestionsColor if not _disableColors
				Console.Write(", ") if i > 0
				if i > 20: #TODO: maxcandidates pref + paging?
					Console.Write("... (too much candidates)")
					break
				if i == _selectedSuggestionIndex:
					Console.ForegroundColor = _selectedSuggestionColor if not _disableColors
				Console.Write(DescribeEntity(e))
				i++

		Console.ResetColor() if not _disableColors
		#Console.CursorTop = cursorTop
		Console.Write(Environment.NewLine)
		ConsolePrintPrompt()
		Console.Write(_line.ToString())
		Console.CursorLeft = cursorLeft

	private static re_open = Regex("\\(", RegexOptions.Singleline)
	private static re_close = Regex("\\)", RegexOptions.Singleline)

	def DisplaySuggestions(query as string):
		#TODO: FIXME: refactor to one regex?
		p_open = re_open.Matches(query).Count
		p_close = re_close.Matches(query).Count
		if p_open > p_close:
			query = query.Split(" ,(\t".ToCharArray(), 100)[-1]
		else:
			query = query.Split(" ,\t".ToCharArray(), 100)[-1]
		if query.LastIndexOf('.') > 0:
			codeToComplete = query[0:query.LastIndexOf('.')+1]
			_suggestions = SuggestCodeCompletion(codeToComplete+"__codecomplete__")
			_filter = query[query.LastIndexOf('.')+1:]
			_suggestions = array(e for e in _suggestions as (IEntity)
								unless not e.Name.StartsWith(_filter)) as (IEntity)

		if not _suggestions or 0 == len(_suggestions): #suggest a  var
			_filter = query
			_suggestions = array(var.ToString() for var in _values.Keys
									unless not var.ToString().StartsWith(_filter))

		if not _suggestions or 0 == len(_suggestions):
			_selectedSuggestionIndex = -1
			#Console.Beep() #TODO: flash background?
		elif 1 == len(_suggestions):
			AutoComplete()
		else:
			ConsolePrintSuggestions()

	def AutoComplete():
		if not _suggestions:
			raise InvalidOperationException("no suggestions")

		s = _suggestions[_selectedSuggestionIndex] as IEntity
		if s:
			if s.EntityType == EntityType.Method:
				m = s as IMethod
				completion = s.Name[len(_filter):]
				Console.Write(completion) #FIXME: insert at cursor!
				_line.Append(completion)
				if not m.GetParameters() or m.GetParameters().Length == 0:
					Console.Write('()') #FIXME: insert at cursor!
					_line.Append('()')
				else:
					Console.Write('(') #FIXME: insert at cursor!
					_line.Append('(')

			else: # not a Method
				completion = s.Name[len(_filter):]
				Console.Write(completion) #FIXME: insert at cursor!
				_line.Append(completion)
		else:
			completion = (_suggestions[_selectedSuggestionIndex] as string)[len(_filter):]
			Console.Write(completion) #FIXME: insert at cursor!
			_line.Append(completion)

		_selectedSuggestionIndex = -1
		_suggestions = null

	private _beforeHistory = string.Empty

	def DisplayHistory():
		if _history.Count == 0 or _historyIndex < 0 or _historyIndex > _history.Count:
			return
		Console.CursorLeft = len(CurrentPrompt)
		Console.Write(string.Empty.PadLeft(_line.Length, char(' ')))
		line = _history.ToArray()[_historyIndex]
		_line.Length = 0
		_line.Append(line)
		Console.CursorLeft = len(CurrentPrompt)
		Console.Write(line)

	def ConsoleLoopEval():
		Console.CursorVisible = true
		ConsolePrintPrompt()

		lastChar = char('0')
		key = ConsoleKey.LeftArrow
		while not _quit:
			cki = Console.ReadKey(true) #TODO: fix mono different behavior when ()
			key = cki.Key
			keyChar = cki.KeyChar
			control = false

			newLine = keyChar in Environment.NewLine

			if char.IsControl(keyChar):
				control = true
				if keyChar == char('\t'):
					test = char(' ')
					test = _line.ToString()[_line.Length-1] if _line.Length > 0
					if char.IsLetterOrDigit(test) or test == char('.'):
						_selectedSuggestionIndex = 0
						DisplaySuggestions(_line.ToString())
					else:
						_line.Append("    ") #TODO: _tabWidth pref
						Console.Write("    ")

				#line-editing support
				if key == ConsoleKey.Backspace:
					if Console.CursorLeft > len(CurrentPrompt) and _line.Length > 0:
						cx = Console.CursorLeft-len(CurrentPrompt)-1
						_line.Remove(cx, 1)
						cx2 = --Console.CursorLeft
						Console.Write("${_line.ToString(cx, _line.Length-cx)} ")
						Console.CursorLeft = cx2
				elif key == ConsoleKey.Delete:
					if Console.CursorLeft >= len(CurrentPrompt) and _line.Length > 0:
						cx = Console.CursorLeft-len(CurrentPrompt)
						if cx < _line.Length:
							_line.Remove(cx, 1)
							cx2 = Console.CursorLeft
							Console.Write("${_line.ToString(cx, _line.Length-cx)} ")
							Console.CursorLeft = cx2
				elif key == ConsoleKey.LeftArrow:
					if Console.CursorLeft > len(CurrentPrompt) and _line.Length > 0:
						Console.CursorLeft--
				elif key == ConsoleKey.RightArrow:
					if Console.CursorLeft < (len(CurrentPrompt)+_line.Length):
						Console.CursorLeft++
				elif key == ConsoleKey.Home:
					Console.CursorLeft = len(CurrentPrompt)
				elif key == ConsoleKey.End:
					Console.CursorLeft = len(CurrentPrompt) + _line.Length

				#history support
				if key == ConsoleKey.UpArrow:
					if _historyIndex > 0:
						_historyIndex--
						DisplayHistory()
				if key == ConsoleKey.DownArrow:
					if _historyIndex < _history.Count-1:
						_historyIndex++
						DisplayHistory()

				#auto-completion support
				if CanAutoComplete:
					if key == ConsoleKey.LeftArrow:
						if _selectedSuggestionIndex > 0:
							_selectedSuggestionIndex--
						else:
							_selectedSuggestionIndex = len(_suggestions)
						DisplaySuggestions(_line.ToString())
					if key == ConsoleKey.RightArrow:
						if _selectedSuggestionIndex+1 < len(_suggestions):
							_selectedSuggestionIndex++
						else:
							_selectedSuggestionIndex = 0
						DisplaySuggestions(_line.ToString())
					if newLine:
						AutoComplete()
						continue
				if not newLine:
					continue

			_selectedSuggestionIndex = -1

			cx = Console.CursorLeft-len(CurrentPrompt)
			line = _line.ToString()

			if not newLine:
				if cx < len(line):	#line-editing support
					_line.Insert(cx, keyChar) if not control
					Console.Write(_line.ToString(cx, _line.Length-cx))
					Console.CursorLeft = len(CurrentPrompt)+cx+1
				else:
					_line.Append(keyChar) if not control
					Console.Write(keyChar)

			line = _line.ToString()

			if newLine:
				Console.Write(Environment.NewLine)

				if not TryRunCommand(line):
					_buffer.Append(line)
					_buffer.Append(Environment.NewLine)
					AddToHistory(line)

					try:
						if len(line) > 0:
							_indent++ if line[len(line)-1] in _blockStarters
							_indent-- if line[len(line)-1] == keyChar and _indent > 0
						else:
							_indent--
						if _indent == 0:
							InternalLoopEval(_buffer.ToString())
							_buffer.Length = 0
					except x as System.Reflection.TargetInvocationException:
						ConsolePrintException(x.InnerException)
					except x:
						ConsolePrintException(x)

					_line.Length = 0
					ConsolePrintPrompt()

			lastChar = keyChar

		SaveHistory()
		DisplayGoodbye()

	/* returns false if no command has been processed, true otherwise */
	def TryRunCommand(line as string):
		if not line.StartsWith("/"):
			return false

		cmd = line.Split()

		if len(cmd) == 1:
			if cmd[0] == "/q" or cmd[0] == "/quit":
				quit()
			elif cmd[0] == "/?" or cmd[0] == "/h" or cmd[0] == "/help":
				DisplayHelp()
				_selectedSuggestionIndex = -1
				_buffer.Length = 0
				ConsolePrintPrompt()
			elif cmd[0] == "/g" or cmd[0] == "/globals":
				globals()
			else:
				return false

		elif len(cmd) == 2:
			if cmd[0] == "/l" or cmd[0] == "/load":
				load(cmd[1])
				_line.Length = 0
				ConsolePrintPrompt()
			elif cmd[0] == "/s" or cmd[0] == "/save":
				save(cmd[1])
				_line.Length = 0
				ConsolePrintPrompt()
			else:
				return false

		else:
			return false
		return true

	private _indent as int = 0

	def LoopEval(code as string):
		using console = ConsoleCapture():
			result = InternalLoopEval(code)
			for line in System.IO.StringReader(console.ToString()):
				_print(line)
		return result

	private def InternalLoopEval(code as string):
		result = self.Eval(code)
		if ShowWarnings:
			self.DisplayProblems(result.Warnings)
		if not self.DisplayProblems(result.Errors):
			ProcessLastValue()
			_session.Add(code)
		return result

	private def ProcessLastValue():
		_ = self.LastValue
		if _ is not null:
			_print(repr(_))
			SetValue("_", _)

	override def Declare([required] name as string,
				[required] type as System.Type):
		_declarations.Add(name, type)

	override def SetLastValue(value):
		_lastValue = value

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

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

	override def Lookup([required] name as string):
		type as System.Type = _declarations[name]
		return type if type is not null

		value = GetValue(name)
		return value.GetType() if value is not null

	def DisplayProblems(problems as ICollection):
		return if problems is null or problems.Count == 0
		Console.ForegroundColor = _exceptionColor if not _disableColors
		for problem as duck in problems:
			markLocation(problem.LexicalInfo)
			type = ("WARNING", "ERROR")[problem isa CompilerError]
			_print("${type}: ${problem.Message}")
		Console.ResetColor() if not _disableColors
		if problems.Count > 0:
			return true
		return false

	private def markLocation(location as LexicalInfo):
		pos = location.Column
		_print("---" + "-" * pos + "^") if pos > 0

	private def InitializeStandardReferences():
		SetValue("interpreter", self)
		SetValue("dir", dir)
		SetValue("help", help)
		SetValue("print", { value | _print(value) })
		SetValue("load", load)
		SetValue("globals", globals)
		SetValue("getRootNamespace", Namespace.GetRootNamespace)

	def DisplayHelp():
		Console.ForegroundColor = _interpreterColor	if not _disableColors
		print """Welcome to booish, an interpreter for the boo programming language.
Running boo ${BooVersion} in CLR v${Environment.Version}.

The following builtin functions are available:
    /d[ir] type : lists the members of a type
    /h[elp] type : prints detailed information about a type
    /l[oad] file : evals an external boo file
    /s[ave] file : writes your current booish session into file
    /g[lobals] : returns names of all variables known to interpreter
    /n[ames] : namespace navigation
    /q[uit] : exits the interpreter

Enter boo code in the prompt below."""
		Console.ResetColor() if not _disableColors

	def DisplayGoodbye():	// booish is friendly
		Console.ForegroundColor = _interpreterColor if not _disableColors
		print ""
		print "All your boo are belong to us!"
		Console.ResetColor() if not _disableColors

	def LoadHistory():
		try:
			using history = File.OpenText(_historyFile):
				while line = history.ReadLine():
					AddToHistory(line)
		except:
			ConsolePrintError("Cannot load history from '${_historyFile}'")

	def AddToHistory(line as string):
		return if 0 == (len(line) - len(Environment.NewLine))
		_history.Dequeue() if _history.Count >= HISTORY_CAPACITY
		line = line.Replace(Environment.NewLine, "")
		_history.Enqueue(line)
		_historyIndex = _history.Count

	def SaveHistory():
		try:
			using sw = System.IO.File.CreateText(_historyFile):
				for line in _history:
					sw.WriteLine(line)
		except:
			ConsolePrintError("Cannot save history to '${_historyFile}'.")

	def globals():
		return array(string, _values.Keys)

	def dir([required] obj):
		type = (obj as Type) or obj.GetType()
		return array(member for member in type.GetMembers()
						unless (method=(member as System.Reflection.MethodInfo))
							and method.IsSpecialName)

	def load([required] path as string):
		if path.EndsWith(".boo"):
			ConsolePrintMessage("Evaluating '${path}' ...")
			result = EvalCompilerInput(FileInput(path))
			if ShowWarnings:
				DisplayProblems(result.Warnings)
			if not DisplayProblems(result.Errors):
				ProcessLastValue()
		else:
			try:
				ConsolePrintMessage("Adding reference to '${path}'")
				References.Add(System.Reflection.Assembly.LoadFrom(path))
			except e:
				ConsolePrintError(e.Message)

	def save([required] path as string):
		if path is string.Empty:
			path = "booish_session.boo"
		elif not path.EndsWith(".boo"):
			path = "${path}.boo"
		try:
			using sw = System.IO.File.CreateText(path):
				for line in _session:
					sw.Write(line)
			ConsolePrintMessage("Session saved to '${path}'.")
		except:
			ConsolePrintError("Cannot save to '${path}'. Check if path is valid and has correct permissions.")

	def help(obj):
		type = (obj as Type) or obj.GetType()
		DescribeType("    ", type)

	private _quit = false
	def quit():
		_quit = true

	def DescribeType(indent as string, type as Type):
		if type.IsInterface:
			typeDef = "interface"
			baseTypes = array(GetBooTypeName(t) for t in type.GetInterfaces())
		else:
			typeDef = "class"
			baseTypes = (GetBooTypeName(type.BaseType),) + array(GetBooTypeName(t) for t in type.GetInterfaces())

		_print("${typeDef} ${type.Name}(${join(baseTypes, ', ')}):")
		_print("")

		for ctor in type.GetConstructors():
			_print("${indent}def constructor(${DescribeParameters(ctor.GetParameters())})")
			_print("")

		sortByName = def (lhs as Reflection.MemberInfo, rhs as Reflection.MemberInfo):
			return lhs.Name.CompareTo(rhs.Name)

		for f as Reflection.FieldInfo in List(type.GetFields()).Sort(sortByName):
			_print("${indent}public ${DescribeField(f)}")
			_print("")

		for p as Reflection.PropertyInfo in List(type.GetProperties()).Sort(sortByName):
			_print("${indent}${DescribeProperty(p)}:")
			_print("${indent}${indent}get") if p.GetGetMethod() is not null
			_print("${indent}${indent}set") if p.GetSetMethod() is not null
			_print("")

		for m as Reflection.MethodInfo in List(type.GetMethods()).Sort(sortByName):
			continue if m.IsSpecialName
			_print("${indent}${DescribeMethod(m)}")
			_print("")

		for e as Reflection.EventInfo in List(type.GetEvents()).Sort(sortByName):
			_print("${indent}${DescribeEvent(e)}")
			_print("")

	static def DescribeEntity(entity as IEntity):
		method = entity as ExternalMethod
		if method is not null:
			return InteractiveInterpreter.DescribeMethod(method.MethodInfo)
		field = entity as ExternalField
		if field is not null:
			return InteractiveInterpreter.DescribeField(field.FieldInfo)
		property = entity as ExternalProperty
		if property is not null:
			return InteractiveInterpreter.DescribeProperty(property.PropertyInfo)
		e = entity as ExternalEvent
		if e is not null:
			return InteractiveInterpreter.DescribeEvent(e.EventInfo)
		return entity.ToString()

	static def DescribeEvent(e as Reflection.EventInfo):
		return "${DescribeModifiers(e)}event ${e.Name} as ${e.EventHandlerType}"

	static def DescribeProperty(p as Reflection.PropertyInfo):
		modifiers = DescribeModifiers(p)
		params = DescribePropertyParameters(p.GetIndexParameters())
		return "${modifiers}${p.Name}${params} as ${GetBooTypeName(p.PropertyType)}"

	static def DescribeField(f as Reflection.FieldInfo):
		return "${DescribeModifiers(f)}${f.Name} as ${GetBooTypeName(f.FieldType)}"

	static def DescribeMethod(m as Reflection.MethodInfo):
		returnType = GetBooTypeName(m.ReturnType)
		modifiers = DescribeModifiers(m)
		return "${modifiers}def ${m.Name}(${DescribeParameters(m.GetParameters())}) as ${returnType}"

	static def DescribeModifiers(f as Reflection.FieldInfo):
		return "static " if f.IsStatic
		return ""

	static def DescribeModifiers(m as Reflection.MethodBase):
		return "static " if m.IsStatic
		return ""

	static def DescribeModifiers(e as Reflection.EventInfo):
		return DescribeModifiers(e.GetAddMethod(true) or e.GetRemoveMethod(true))

	static def DescribeModifiers(p as Reflection.PropertyInfo):
		accessor = p.GetGetMethod(true) or p.GetSetMethod(true)
		return DescribeModifiers(accessor)

	static def DescribePropertyParameters(parameters as (Reflection.ParameterInfo)):
		return "" if 0 == len(parameters)
		return "(${DescribeParameters(parameters)})"

	static def DescribeParameters(parameters as (Reflection.ParameterInfo)):
		return join(DescribeParameter(p) for p in parameters, ", ")

	static def DescribeParameter(p as Reflection.ParameterInfo):
		return "${p.Name} as ${GetBooTypeName(p.ParameterType)}"

	static def GetBooTypeName(type as System.Type) as string:
		return "(${GetBooTypeName(type.GetElementType())})" if type.IsArray
		return "object" if object is type
		return "string" if string is type
		return "void" if void is type
		return "bool" if bool is type
		return "byte" if byte is type
		return "char" if char is type
		return "sbyte" if sbyte is type
		return "short" if short is type
		return "ushort" if ushort is type
		return "int" if int is type
		return "uint" if uint is type
		return "long" if long is type
		return "ulong" if ulong is type
		return "single" if single is type
		return "double" if double is type
		return "date" if date is type
		return "timespan" if timespan is type
		return "regex" if regex is type
		return type.FullName

	def repr(value):
		writer = System.IO.StringWriter()
		repr(value, writer)
		return writer.ToString()

	def repr(value, writer as System.IO.TextWriter):
		return unless value is not null
		InitializeRepresenters() if 0 == len(_representers)
		GetBestRepresenter(value.GetType())(value, writer)

	private def InitializeRepresenters():
		AddRepresenter(string) do (value as string, writer as TextWriter):
			Visitors.BooPrinterVisitor.WriteStringLiteral(value, writer)

		AddRepresenter(bool) do (value as bool, writer as TextWriter):
			writer.Write(("false", "true")[value])

		AddRepresenter(Array) do (a as Array, writer as TextWriter):
			writer.Write("(")
			RepresentItems(a, writer)
			writer.Write(")")

		AddRepresenter(Delegate) do (d as Delegate, writer as TextWriter):
			method = d.Method
			writer.Write(method.DeclaringType.FullName)
			writer.Write(".")
			writer.Write(method.Name)

		AddRepresenter(IDictionary) do (value as IDictionary, writer as TextWriter):
			writer.Write("{")
			i = 0
			for key in value.Keys:
				writer.Write(", ") if i
				repr(key, writer)
				writer.Write(": ")
				repr(value[key], writer)
				++i
			writer.Write("}")

		AddRepresenter(IList) do (value as IList, writer as TextWriter):
			writer.Write("[")
			RepresentItems(value, writer)
			writer.Write("]")

		AddRepresenter(object) do (value, writer as TextWriter):
			writer.Write(value)

	private def RepresentItems(items, writer as TextWriter):
		i = 0
		for item in items:
			writer.Write(", ") if i > 0
			repr(item, writer)
			++i

	callable Representer(value, writer as TextWriter)

	private def AddRepresenter(type as Type, value as Representer):
		_representers.Add((type, value))

	def GetBestRepresenter(type as Type) as Representer:
		for key as Type, value in _representers:
			return value if key.IsAssignableFrom(type)
		assert false, "An appropriate representer could not be found!"


adapted test

adapted test

"""
"""
assert len(BOO_RUNTIME_VERSION) > 0
assert len(BOO_COMPILER_VERSION) > 0
assert BOO_COMPILER_VERSION != '%%' + 'COMPILER_VERSION' + '%%'


fixed test case

fixed test case

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

"""
BCE0058-1.boo(9,15): BCE0058: 'self' is not valid in a static method, static property, or static field initializer.
BCE0058-1.boo(12,15): BCE0058: 'self' is not valid in a static method, static property, or static field initializer.
BCE0058-1.boo(14,10): BCE0058: 'self' is not valid in a static method, static property, or static field initializer.
BCE0058-1.boo(18,20): BCE0058: 'self' is not valid in a static method, static property, or static field initializer.
"""
static class Foo:
	def constructor():
		print self

	def bar():
		print self

	_x = self

	Prop:
		get:
			return self

"""
BCE0058-1.boo(7,15): BCE0058: 'self' is not valid in a static method, static property, or static field initializer.
BCE0058-1.boo(10,15): BCE0058: 'self' is not valid in a static method, static property, or static field initializer.
BCE0058-1.boo(12,10): BCE0058: 'self' is not valid in a static method, static property, or static field initializer.
BCE0058-1.boo(16,20): BCE0058: 'self' is not valid in a static method, static property, or static field initializer.
"""
static class Foo:
	def constructor():
		print self

	def bar():
		print self

	_x = self

	Prop:
		get:
			return self


booish loop example

booish loop example

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

namespace booish

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

class InterpreterEntity(ITypedEntity):

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

	[getter(Type)]
	_type as IType

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

	EntityType:
		get:
			return TypeSystem.EntityType.Custom

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

class InterpreterNamespace(INamespace):

	[getter(ParentNamespace)]
	_parent as INamespace

	_tss as TypeSystemServices

	_interpreter as InteractiveInterpreter

	_declarations = {}

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

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

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

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

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

		return false

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

class ProcessVariableDeclarations(Steps.ProcessMethodBodiesWithDuckTyping):

	_namespace as InterpreterNamespace
	_interpreter as InteractiveInterpreter

	def constructor(interpreter):
		_interpreter = interpreter

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

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

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

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

class ProcessInterpreterReferences(Steps.AbstractTransformerCompilerStep):

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

	_interpreterField as Field
	_namespace as InterpreterNamespace
	_interpreter as InteractiveInterpreter

	def constructor(interpreter):
		_interpreter = interpreter

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

	override def OnModule(node as Module):

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

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

		super(node)

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

		ReplaceCurrentNode(CreateGetValue(node))

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

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

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

class InteractiveInterpreter:

	_compiler = BooCompiler()

	_values = {}

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

		_compiler.Parameters.Pipeline = pipeline

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

namespace booish

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

class InterpreterEntity(ITypedEntity):

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

	[getter(Type)]
	_type as IType

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

	EntityType:
		get:
			return TypeSystem.EntityType.Custom

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

class InterpreterNamespace(INamespace):

	[getter(ParentNamespace)]
	_parent as INamespace

	_tss as TypeSystemServices

	_interpreter as InteractiveInterpreter

	_declarations = {}

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

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

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

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

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

		return false

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

class ProcessVariableDeclarations(Steps.ProcessMethodBodiesWithDuckTyping):

	_namespace as InterpreterNamespace
	_interpreter as InteractiveInterpreter

	def constructor(interpreter):
		_interpreter = interpreter

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

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

	override def ProcessAssignment(node as BinaryExpression):
		super(node) unless InterpreterEntity.IsInterpreterEntity(node.Left)

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

class ProcessInterpreterReferences(Steps.AbstractTransformerCompilerStep):

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

	_interpreterField as Field
	_namespace as InterpreterNamespace
	_interpreter as InteractiveInterpreter

	def constructor(interpreter):
		_interpreter = interpreter

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

	override def OnModule(node as Module):

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

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

		super(node)

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

		ReplaceCurrentNode(CreateGetValue(node))

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

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

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

class InteractiveInterpreter:

	_compiler = BooCompiler()

	_values = {}

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

		_compiler.Parameters.Pipeline = pipeline

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

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

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

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

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

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

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

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

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

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

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

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

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

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