Use sequence instead of self execution functions

namespace BooJs.Compiler.Steps

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

class NormalizeGeneratorExpression(AbstractTransformerCompilerStep):
"""
    Converts generator expressions to a simpler format:

        ( i*2 for i in range(3) )
        ---
        { __gen = []; for i in range(3): __gen.push(i*2); return __gen }()
"""

    # Keep track of last visited method
    _method as Method
    def OnMethod(node as Method):
        last = _method
        _method = node
        super(node)
        _method = last

    def OnListLiteralExpression(node as ListLiteralExpression):
    """ If generator is contained in a list literal, remove the list literal
    """
        if len(node.Items) == 1 and node.Items.First.NodeType == NodeType.GeneratorExpression:
            result = Visit(node.Items.First)
            ReplaceCurrentNode result
            return

        super(node)

    def LeaveGeneratorExpression(node as GeneratorExpression):
    """ Convert generator expressions to a sequence:

        ( i*2 for i in range(3) )  =>  @(__gen = [], Boo.each(range(3), { i | __gen.push(i*2) }), __gen)

    """
        # Make sure the __gen variable is declared
        _method.Locals.Add(Local(node.LexicalInfo, '__gen'))

        if node.Filter:
            lambda = [| { $(node.Filter.Condition) and __gen.push( $(node.Expression) ) } |]
        else:
            lambda = [| { __gen.push( $(node.Expression) ) } |]

        lambda.LexicalInfo = node.LexicalInfo
        for decl in node.Declarations:
            lambda.Parameters.Add(ParameterDeclaration(node.LexicalInfo, Name: decl.Name))

        result = [| @(__gen = [], Boo.each($(node.Iterator), $lambda), __gen) |]
        ReplaceCurrentNode result

namespace BooJs.Compiler.Steps

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

class NormalizeGeneratorExpression(AbstractTransformerCompilerStep):
"""
    Converts generator expressions to a simpler format:

        ( i*2 for i in range(3) )
        ---
        { __gen = []; for i in range(3): __gen.push(i*2); return __gen }()
"""
    def LeaveGeneratorExpression(node as GeneratorExpression):
        # ( i*2 for i as int in range(3) )  =>  ( expression for declarations in iterator if filter )

        # Build a loop statement with the details from the generator
        loop = ForStatement()
        loop.Declarations = node.Declarations
        loop.Iterator = node.Iterator
        if not node.Filter:
            loop.Block = [|
                block:
                    _gen.push($(node.Expression))
            |].Body
        else:
            loop.Block = [|
                block:
                    _gen.push($(node.Expression)) if $(node.Filter.Condition)
            |].Body

        # Build the body of the anonymous function
        body = [|
            block:
                $loop
                return _gen
        |].Body

        # Replace the generator expression with the result of executing the anonymous function
        ReplaceCurrentNode([| {_gen as (object)| $(body) }([]) |])


updated to latest boo trunk

updated to latest boo trunk

namespace UnityScript.Steps

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

import Boo.Lang.Environments

import UnityScript.Macros

class ProcessUnityScriptMethods(ProcessMethodBodiesWithDuckTyping):

	deferred IEnumerable_GetEnumerator = Types.IEnumerable.GetMethod("GetEnumerator");

	deferred IEnumerator_MoveNext = Types.IEnumerator.GetMethod("MoveNext");

	deferred IEnumerator_get_Current = Types.IEnumerator.GetProperty("Current").GetGetMethod();

	deferred _StartCoroutine = NameResolutionService.ResolveMethod(UnityScriptTypeSystem.ScriptBaseType, "StartCoroutine_Auto")

	deferred _UnityRuntimeServices_GetEnumerator = ResolveUnityRuntimeMethod("GetEnumerator")

	deferred _UnityRuntimeServices_Update = ResolveUnityRuntimeMethod("Update")

	deferred _UnityRuntimeServices_GetTypeOf = ResolveUnityRuntimeMethod("GetTypeOf")

	_strict = false

	_implicit = false

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

		// don't transform
		//     foo == null
		// into:
		//     foo is null
		// but into:
		//     foo.Equals(null)
		self.OptimizeNullComparisons = false

	def ResolveUnityRuntimeMethod(name as string):
		return NameResolutionService.ResolveMethod(TypeSystemServices.Map(UnityScript.Lang.UnityRuntimeServices), name)

	UnityScriptTypeSystem as UnityScript.Steps.UnityScriptTypeSystem:
		get: return self.TypeSystemServices

	UnityScriptParameters as UnityScript.UnityScriptCompilerParameters:
		get: return _context.Parameters

	override def GetGeneratorReturnType(generator as InternalMethod):
		return TypeSystemServices.IEnumeratorType

	override def IsDuckTyped(e as Expression):
		if _strict: return false
		return super(e)

	override def IsDuckTyped(member as IMember):
		if _strict: return false
		return super(member)

	override protected def MemberNotFound(node as MemberReferenceExpression, ns as INamespace):
		if (not _strict) and (UnityScriptParameters.Expando or super.IsDuckTyped(node.Target)):
			BindQuack(node);
			return
		super(node, ns)

	override def OnModule(module as Module):
		Parameters.Strict = _strict = module.ContainsAnnotation("strict")
		_implicit = module.ContainsAnnotation("implicit")
		my(UnityDowncastPermissions).Enabled = module.ContainsAnnotation("downcast")
		super(module)

	override def OnMethod(node as Method):
		super(node)
		return if Parameters.OutputType == CompilerOutputType.Library
		CheckEntryPoint(node)

	def CheckEntryPoint(node as Method):
		if not node.IsStatic: return
		if not node.IsPublic: return
		if node.Name != "Main": return
		if GetType(node.ReturnType) is not TypeSystemServices.VoidType: return

		ContextAnnotations.SetEntryPoint(_context, node)

	override def ProcessAutoLocalDeclaration(node as BinaryExpression, reference as ReferenceExpression):
		if (_strict and not _implicit) and not IsCompilerGenerated(reference):
			EmitUnknownIdentifierError(reference, reference.Name)
		else:
			super(node, reference)

	def IsCompilerGenerated(reference as ReferenceExpression):
		return reference.Name.Contains('$')

	override protected def ProcessBuiltinInvocation(function as BuiltinFunction, node as MethodInvocationExpression):
		if function is UnityScriptTypeSystem.UnityScriptEval:
			ProcessEvalInvocations.Mark(_currentMethod.Method)
			BindExpressionType(node, TypeSystemServices.ObjectType)
			return
		if function is UnityScriptTypeSystem.UnityScriptTypeof:
			ProcessTypeofBuiltin(node);
			return
		super(function, node)

	private def ProcessTypeofBuiltin(node as MethodInvocationExpression):
		if node.Arguments.Count != 1:
			Error(node, CompilerError("UCE0001", node.Target.LexicalInfo, "'typeof' takes a single argument.", null))
			return

		type = TypeSystemServices.GetOptionalEntity(node.Arguments[0]) as IType
		if type is not null:
			node.ParentNode.Replace(node, CodeBuilder.CreateTypeofExpression(type))
			return

		node.Target = CodeBuilder.CreateReference(_UnityRuntimeServices_GetTypeOf)
		BindExpressionType(node, TypeSystemServices.TypeType)

	override protected def ProcessMethodInvocation(node as MethodInvocationExpression, targetEntity as IEntity):
	"""
	Automatically detects coroutine invocations in assignments and as standalone
	expressions and generates StartCoroutine invocations.
	"""
		super(node, targetEntity)

		if not IsPossibleStartCoroutineInvocation(node):
			return

		method as IMethod = targetEntity
		if method is null or method.IsStatic: return

		tss = self.UnityScriptTypeSystem
		if not tss.IsScriptType(method.DeclaringType): return
		if not tss.IsGenerator(method): return

		parentNode = node.ParentNode
		parentNode.Replace(
			node,
			CodeBuilder.CreateMethodInvocation(
				cast(MemberReferenceExpression, node.Target).Target.CloneNode(),
				_StartCoroutine,
				node))

	override def ProcessStaticallyTypedAssignment(node as BinaryExpression):
		TryToResolveAmbiguousAssignment(node)
		ApplyImplicitArrayConversion(node)
		ValidateAssignment(node)
		BindExpressionType(node, GetExpressionType(node.Right))

	def ApplyImplicitArrayConversion(node as BinaryExpression):
		left = GetExpressionType(node.Left)
		if not left.IsArray: return

		right = GetExpressionType(node.Right)
		if right is not TypeSystemServices.Map(UnityScript.Lang.Array): return

		node.Right = CodeBuilder.CreateCast(left,
						CodeBuilder.CreateMethodInvocation(
							node.Right,
							ResolveMethod(right, "ToBuiltin"),
							CodeBuilder.CreateTypeofExpression(left.GetElementType())))

	override def OnForStatement(node as ForStatement):
		assert 1 == len(node.Declarations)
		Visit(node.Iterator)
		if NeedsUpdateableIteration(node):
			ProcessUpdateableIteration(node)
		else:
			ProcessNormalIteration(node)

	def ProcessNormalIteration(node as ForStatement):
		node.Iterator = ProcessIterator(node.Iterator, node.Declarations)
		VisitForStatementBlock(node)

	def ProcessUpdateableIteration(node as ForStatement):
		newIterator = CodeBuilder.CreateMethodInvocation(_UnityRuntimeServices_GetEnumerator, node.Iterator)
		newIterator.LexicalInfo = LexicalInfo(node.Iterator.LexicalInfo)
		node.Iterator = newIterator
		ProcessDeclarationForIterator(node.Declarations[0], TypeSystemServices.ObjectType)
		VisitForStatementBlock(node)
		TransformIteration(node)

	def TransformIteration(node as ForStatement):
		iterator = CodeBuilder.DeclareLocal(
						_currentMethod.Method,
						_context.GetUniqueName("iterator"),
						TypeSystemServices.IEnumeratorType)
		iterator.IsUsed = true
		body = Block(node.LexicalInfo)
		body.Add(
			CodeBuilder.CreateAssignment(
				node.LexicalInfo,
				CodeBuilder.CreateReference(iterator),
				node.Iterator))

		// while __iterator.MoveNext():
		ws = WhileStatement(node.LexicalInfo)
		ws.Condition = CodeBuilder.CreateMethodInvocation(
						CodeBuilder.CreateReference(iterator),
						IEnumerator_MoveNext)

		current = CodeBuilder.CreateMethodInvocation(
							CodeBuilder.CreateReference(iterator),
							IEnumerator_get_Current)

		//	item = __iterator.Current
		loopVariable as InternalLocal = TypeSystemServices.GetEntity(node.Declarations[0])
		ws.Block.Add(
				CodeBuilder.CreateAssignment(
					node.LexicalInfo,
					CodeBuilder.CreateReference(loopVariable),
					current))
		ws.Block.Add(node.Block)

		LoopVariableUpdater(self, _context, iterator, loopVariable).Visit(node)

		body.Add(ws)
		node.ParentNode.Replace(node, body)

	def NeedsUpdateableIteration(node as ForStatement):
		iteratorType = GetExpressionType(node.Iterator)
		if iteratorType.IsArray: return false
		return true

	class LoopVariableUpdater(DepthFirstVisitor):

		_parent as ProcessUnityScriptMethods
		_context as CompilerContext
		_iteratorVariable as IEntity
		_loopVariable as IEntity
		_found as bool

		def constructor(parent as ProcessUnityScriptMethods, context as CompilerContext, iteratorVariable as IEntity, loopVariable as IEntity):
			_parent = parent
			_context = context
			_iteratorVariable = iteratorVariable
			_loopVariable = loopVariable

		override def OnExpressionStatement(node as ExpressionStatement):
			_found = false
			Visit(node.Expression)
			if not _found: return

			parentNode = node.ParentNode

			codeBuilder = _context.CodeBuilder
			block = Block(node.LexicalInfo)
			block.Add(node)
			block.Add(
				codeBuilder.CreateMethodInvocation(
					_parent._UnityRuntimeServices_Update,
					codeBuilder.CreateReference(_iteratorVariable),
					codeBuilder.CreateReference(_loopVariable)))

			parentNode.Replace(node, block)

		override def OnReferenceExpression(node as ReferenceExpression):
			if _found: return

			referent = _context.TypeSystemServices.GetOptionalEntity(node)
			_found = referent is _loopVariable

namespace UnityScript.Steps

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.TypeSystem.Internal
import Boo.Lang.Compiler.TypeSystem.Services
import Boo.Lang.Compiler.Steps
import UnityScript.Macros

class ProcessUnityScriptMethods(ProcessMethodBodiesWithDuckTyping):

	deferred IEnumerable_GetEnumerator = Types.IEnumerable.GetMethod("GetEnumerator");

	deferred IEnumerator_MoveNext = Types.IEnumerator.GetMethod("MoveNext");

	deferred IEnumerator_get_Current = Types.IEnumerator.GetProperty("Current").GetGetMethod();

	deferred _StartCoroutine = NameResolutionService.ResolveMethod(UnityScriptTypeSystem.ScriptBaseType, "StartCoroutine_Auto")

	deferred _UnityRuntimeServices_GetEnumerator = ResolveUnityRuntimeMethod("GetEnumerator")

	deferred _UnityRuntimeServices_Update = ResolveUnityRuntimeMethod("Update")

	deferred _UnityRuntimeServices_GetTypeOf = ResolveUnityRuntimeMethod("GetTypeOf")

	_strict = false

	_implicit = false

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

		// don't transform
		//     foo == null
		// into:
		//     foo is null
		// but into:
		//     foo.Equals(null)
		self.OptimizeNullComparisons = false

	def ResolveUnityRuntimeMethod(name as string):
		return NameResolutionService.ResolveMethod(TypeSystemServices.Map(UnityScript.Lang.UnityRuntimeServices), name)

	UnityScriptTypeSystem as UnityScript.Steps.UnityScriptTypeSystem:
		get: return self.TypeSystemServices

	UnityScriptParameters as UnityScript.UnityScriptCompilerParameters:
		get: return _context.Parameters

	override def GetGeneratorReturnType(generator as InternalMethod):
		return TypeSystemServices.IEnumeratorType

	override def IsDuckTyped(e as Expression):
		if _strict: return false
		return super(e)

	override def IsDuckTyped(member as IMember):
		if _strict: return false
		return super(member)

	override protected def MemberNotFound(node as MemberReferenceExpression, ns as INamespace):
		if (not _strict) and (UnityScriptParameters.Expando or super.IsDuckTyped(node.Target)):
			BindQuack(node);
			return
		super(node, ns)

	override def OnModule(module as Module):
		Parameters.Strict = _strict = module.ContainsAnnotation("strict")
		_implicit = module.ContainsAnnotation("implicit")
		my(UnityDowncastPermissions).Enabled = module.ContainsAnnotation("downcast")
		super(module)

	override def OnMethod(node as Method):
		super(node)
		return if Parameters.OutputType == CompilerOutputType.Library
		CheckEntryPoint(node)

	def CheckEntryPoint(node as Method):
		if not node.IsStatic: return
		if not node.IsPublic: return
		if node.Name != "Main": return
		if GetType(node.ReturnType) is not TypeSystemServices.VoidType: return

		ContextAnnotations.SetEntryPoint(_context, node)

	override def ProcessAutoLocalDeclaration(node as BinaryExpression, reference as ReferenceExpression):
		if (_strict and not _implicit) and not IsCompilerGenerated(reference):
			EmitUnknownIdentifierError(reference, reference.Name)
		else:
			super(node, reference)

	def IsCompilerGenerated(reference as ReferenceExpression):
		return reference.Name.Contains('$')

	override protected def ProcessBuiltinInvocation(function as BuiltinFunction, node as MethodInvocationExpression):
		if function is UnityScriptTypeSystem.UnityScriptEval:
			ProcessEvalInvocations.Mark(_currentMethod.Method)
			BindExpressionType(node, TypeSystemServices.ObjectType)
			return
		if function is UnityScriptTypeSystem.UnityScriptTypeof:
			ProcessTypeofBuiltin(node);
			return
		super(function, node)

	private def ProcessTypeofBuiltin(node as MethodInvocationExpression):
		if node.Arguments.Count != 1:
			Error(node, CompilerError("UCE0001", node.Target.LexicalInfo, "'typeof' takes a single argument.", null))
			return

		type = TypeSystemServices.GetOptionalEntity(node.Arguments[0]) as IType
		if type is not null:
			node.ParentNode.Replace(node, CodeBuilder.CreateTypeofExpression(type))
			return

		node.Target = CodeBuilder.CreateReference(_UnityRuntimeServices_GetTypeOf)
		BindExpressionType(node, TypeSystemServices.TypeType)

	override protected def ProcessMethodInvocation(node as MethodInvocationExpression, targetEntity as IEntity):
	"""
	Automatically detects coroutine invocations in assignments and as standalone
	expressions and generates StartCoroutine invocations.
	"""
		super(node, targetEntity)

		if not IsPossibleStartCoroutineInvocation(node):
			return

		method as IMethod = targetEntity
		if method is null or method.IsStatic: return

		tss = self.UnityScriptTypeSystem
		if not tss.IsScriptType(method.DeclaringType): return
		if not tss.IsGenerator(method): return

		parentNode = node.ParentNode
		parentNode.Replace(
			node,
			CodeBuilder.CreateMethodInvocation(
				cast(MemberReferenceExpression, node.Target).Target.CloneNode(),
				_StartCoroutine,
				node))

	override def ProcessStaticallyTypedAssignment(node as BinaryExpression):
		TryToResolveAmbiguousAssignment(node)
		ApplyImplicitArrayConversion(node)
		ValidateAssignment(node)
		BindExpressionType(node, GetExpressionType(node.Right))

	def ApplyImplicitArrayConversion(node as BinaryExpression):
		left = GetExpressionType(node.Left)
		if not left.IsArray: return

		right = GetExpressionType(node.Right)
		if right is not TypeSystemServices.Map(UnityScript.Lang.Array): return

		node.Right = CodeBuilder.CreateCast(left,
						CodeBuilder.CreateMethodInvocation(
							node.Right,
							ResolveMethod(right, "ToBuiltin"),
							CodeBuilder.CreateTypeofExpression(left.GetElementType())))

	override def OnForStatement(node as ForStatement):
		assert 1 == len(node.Declarations)
		Visit(node.Iterator)
		if NeedsUpdateableIteration(node):
			ProcessUpdateableIteration(node)
		else:
			ProcessNormalIteration(node)

	def ProcessNormalIteration(node as ForStatement):
		node.Iterator = ProcessIterator(node.Iterator, node.Declarations)
		VisitForStatementBlock(node)

	def ProcessUpdateableIteration(node as ForStatement):
		newIterator = CodeBuilder.CreateMethodInvocation(_UnityRuntimeServices_GetEnumerator, node.Iterator)
		newIterator.LexicalInfo = LexicalInfo(node.Iterator.LexicalInfo)
		node.Iterator = newIterator
		ProcessDeclarationForIterator(node.Declarations[0], TypeSystemServices.ObjectType)
		VisitForStatementBlock(node)
		TransformIteration(node)

	def TransformIteration(node as ForStatement):
		iterator = CodeBuilder.DeclareLocal(
						_currentMethod.Method,
						_context.GetUniqueName("iterator"),
						TypeSystemServices.IEnumeratorType)
		iterator.IsUsed = true
		body = Block(node.LexicalInfo)
		body.Add(
			CodeBuilder.CreateAssignment(
				node.LexicalInfo,
				CodeBuilder.CreateReference(iterator),
				node.Iterator))

		// while __iterator.MoveNext():
		ws = WhileStatement(node.LexicalInfo)
		ws.Condition = CodeBuilder.CreateMethodInvocation(
						CodeBuilder.CreateReference(iterator),
						IEnumerator_MoveNext)

		current = CodeBuilder.CreateMethodInvocation(
							CodeBuilder.CreateReference(iterator),
							IEnumerator_get_Current)

		//	item = __iterator.Current
		loopVariable as InternalLocal = TypeSystemServices.GetEntity(node.Declarations[0])
		ws.Block.Add(
				CodeBuilder.CreateAssignment(
					node.LexicalInfo,
					CodeBuilder.CreateReference(loopVariable),
					current))
		ws.Block.Add(node.Block)

		LoopVariableUpdater(self, _context, iterator, loopVariable).Visit(node)

		body.Add(ws)
		node.ParentNode.Replace(node, body)

	def NeedsUpdateableIteration(node as ForStatement):
		iteratorType = GetExpressionType(node.Iterator)
		if iteratorType.IsArray: return false
		return true

	class LoopVariableUpdater(DepthFirstVisitor):

		_parent as ProcessUnityScriptMethods
		_context as CompilerContext
		_iteratorVariable as IEntity
		_loopVariable as IEntity
		_found as bool

		def constructor(parent as ProcessUnityScriptMethods, context as CompilerContext, iteratorVariable as IEntity, loopVariable as IEntity):
			_parent = parent
			_context = context
			_iteratorVariable = iteratorVariable
			_loopVariable = loopVariable

		override def OnExpressionStatement(node as ExpressionStatement):
			_found = false
			Visit(node.Expression)
			if not _found: return

			parentNode = node.ParentNode

			codeBuilder = _context.CodeBuilder
			block = Block(node.LexicalInfo)
			block.Add(node)
			block.Add(
				codeBuilder.CreateMethodInvocation(
					_parent._UnityRuntimeServices_Update,
					codeBuilder.CreateReference(_iteratorVariable),
					codeBuilder.CreateReference(_loopVariable)))

			parentNode.Replace(node, block)

		override def OnReferenceExpression(node as ReferenceExpression):
			if _found: return

			referent = _context.TypeSystemServices.GetOptionalEntity(node)
			_found = referent is _loopVariable


gently deprecates -ducky command line option

namespace us

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

class CommandLineOptions(AbstractCommandLine):

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

	[getter(Resources)]
	_resources = List of string()

	[getter(OutputType)]
	_outputTarget = CompilerOutputType.Library

	[getter(Imports)]
	_imports = List of string()

	[getter(SourceFiles)]
	_sourceFiles = List of string()

	[getter(SourceDirs)]
	_srcDirs = List of string()

	[getter(SuppressedWarnings)]
	_suppressedWarnings = List of string()

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

	[getter(Pragmas)]
	_pragmas = List of string()

	def constructor(*argv as (string)):
		Parse(argv)

	def ForEachSourceFile(action as Action of string):

		for srcFile as string in _sourceFiles:
			action(srcFile)

		for srcDir in _srcDirs:
			Useful.IO.forEachFileIn(srcDir, "*.js", action)

	IsValid:
		get:
			return (len(self.BaseClass) > 0
					and len(self.MainMethod) > 0
					and	(len(self.SourceFiles) > 0
						or len(self.SourceDirs) > 0))

	[Option("Option has been deprecated", LongForm: "ducky")]
	def DuckyHasBeenDeprecated(value):
		Console.Error.WriteLine("WARNING: -ducky command line option has been deprecated and has no effect")

	[Option("Specifies the output {file} name", ShortForm: "o", LongForm: "out")]
	public Output  = ""

	[Option("Base {class} for the script module", ShortForm: "b", LongForm: "base")]
	public BaseClass = ""

	[Option("Module's main method {name}", ShortForm: 'm', LongForm: "method")]
	public MainMethod = ""

	[Option("Print the resulting code (in boo). Do not generate an assembly.", ShortForm: 'p', LongForm: "print")]
	public PrintCode = false

	[Option("Execute resulting main method.", ShortForm: 'x', LongForm: 'execute')]
	public Execute = false

	[Option("Enable expando mode.", LongForm: "expando")]
	public Expando = false

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

	[Option("Displays internal compiler information", LongForm: "debug-compiler")]
	public DebugCompiler = false

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

	[Option("Disables eval builtin.", LongForm: "disable-eval")]
	public DisableEval as string

	[Option("Enables a comma separated {set} of #pragma directives on every module", LongForm: "pragmas", MaxOccurs: int.MaxValue)]
	def AddPragmas(pragmas as string):
		_pragmas.ExtendUnique(pragma.Trim() for pragma in pragmas.Split(char(',')))

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

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

	[Option("Embed a managed resource {file}", LongForm: "resource", MaxOccurs: int.MaxValue)]
	def AddResource(resource as string):
		_resources.AddUnique(Unquote(resource))

	[Option("Suppress the warning {code}", LongForm: "nowarn", MaxOccurs: int.MaxValue)]
	def SuppressWarning(code as string):
		_suppressedWarnings.Add(code)

	[Option("Specifies the target ({kind} is one of: exe, winexe, library)", ShortForm: 't', LongForm: "target")]
	def SetTarget(kind as string):
		if kind == "library":
			_outputTarget = CompilerOutputType.Library
		elif kind == "exe":
			_outputTarget = CompilerOutputType.ConsoleApplication
		elif kind == "winexe":
			_outputTarget = CompilerOutputType.WindowsApplication
		else:
			InvalidOption(" Valid options for -target: are exe, winexe, library or module")

	[Option("Adds a 'import {namespace}' to the script module", ShortForm: 'i', LongForm: "import", MaxOccurs: int.MaxValue)]
	def AddImport(ns as string):
		_imports.Add(ns)

	[Option("Defines a symbol", ShortForm: 'd', LongForm: "define", MaxOccurs: int.MaxValue)]
	def AddDefine(symbol as string):
		_defines.Add(symbol)

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

	[Argument]
	def AddSourceFile([required] sourceFile as string):
		self.SourceFiles.Add(Unquote(sourceFile))

	private def InvalidOption(msg as string):
		raise msg

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

namespace us

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

class CommandLineOptions(AbstractCommandLine):

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

	[getter(Resources)]
	_resources = List of string()

	[getter(OutputType)]
	_outputTarget = CompilerOutputType.Library

	[getter(Imports)]
	_imports = List of string()

	[getter(SourceFiles)]
	_sourceFiles = List of string()

	[getter(SourceDirs)]
	_srcDirs = List of string()

	[getter(SuppressedWarnings)]
	_suppressedWarnings = List of string()

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

	[getter(Pragmas)]
	_pragmas = List of string()

	def constructor(*argv as (string)):
		Parse(argv)

	def ForEachSourceFile(action as Action of string):

		for srcFile as string in _sourceFiles:
			action(srcFile)

		for srcDir in _srcDirs:
			Useful.IO.forEachFileIn(srcDir, "*.js", action)

	IsValid:
		get:
			return (len(self.BaseClass) > 0
					and len(self.MainMethod) > 0
					and	(len(self.SourceFiles) > 0
						or len(self.SourceDirs) > 0))

	[Option("Specifies the output {file} name", ShortForm: "o", LongForm: "out")]
	public Output  = ""

	[Option("Base {class} for the script module", ShortForm: "b", LongForm: "base")]
	public BaseClass = ""

	[Option("Module's main method {name}", ShortForm: 'm', LongForm: "method")]
	public MainMethod = ""

	[Option("Print the resulting code (in boo). Do not generate an assembly.", ShortForm: 'p', LongForm: "print")]
	public PrintCode = false

	[Option("Execute resulting main method.", ShortForm: 'x', LongForm: 'execute')]
	public Execute = false

	[Option("Enable expando mode.", LongForm: "expando")]
	public Expando = false

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

	[Option("Displays internal compiler information", LongForm: "debug-compiler")]
	public DebugCompiler = false

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

	[Option("Disables eval builtin.", LongForm: "disable-eval")]
	public DisableEval as string

	[Option("Enables a comma separated {set} of #pragma directives on every module", LongForm: "pragmas", MaxOccurs: int.MaxValue)]
	def AddPragmas(pragmas as string):
		_pragmas.ExtendUnique(pragma.Trim() for pragma in pragmas.Split(char(',')))

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

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

	[Option("Embed a managed resource {file}", LongForm: "resource", MaxOccurs: int.MaxValue)]
	def AddResource(resource as string):
		_resources.AddUnique(Unquote(resource))

	[Option("Suppress the warning {code}", LongForm: "nowarn", MaxOccurs: int.MaxValue)]
	def SuppressWarning(code as string):
		_suppressedWarnings.Add(code)

	[Option("Specifies the target ({kind} is one of: exe, winexe, library)", ShortForm: 't', LongForm: "target")]
	def SetTarget(kind as string):
		if kind == "library":
			_outputTarget = CompilerOutputType.Library
		elif kind == "exe":
			_outputTarget = CompilerOutputType.ConsoleApplication
		elif kind == "winexe":
			_outputTarget = CompilerOutputType.WindowsApplication
		else:
			InvalidOption(" Valid options for -target: are exe, winexe, library or module")

	[Option("Adds a 'import {namespace}' to the script module", ShortForm: 'i', LongForm: "import", MaxOccurs: int.MaxValue)]
	def AddImport(ns as string):
		_imports.Add(ns)

	[Option("Defines a symbol", ShortForm: 'd', LongForm: "define", MaxOccurs: int.MaxValue)]
	def AddDefine(symbol as string):
		_defines.Add(symbol)

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

	[Argument]
	def AddSourceFile([required] sourceFile as string):
		self.SourceFiles.Add(Unquote(sourceFile))

	private def InvalidOption(msg as string):
		raise msg

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


exec superceded by load

exec superceded by load

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

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

"""
Interactive Forms-based Console
"""
namespace booish.gui

import System
import System.Drawing
import System.IO
import System.Windows.Forms
import ICSharpCode.TextEditor
import ICSharpCode.TextEditor.Document
import ICSharpCode.TextEditor.Actions
import ICSharpCode.TextEditor.Gui.CompletionWindow
import Boo.Lang.Compiler.TypeSystem

interface ICompletionWindowImageProvider:
	ImageList as ImageList:
		get
	NamespaceIndex as int:
		get
	ClassIndex as int:
		get
	InterfaceIndex as int:
		get
	EnumIndex as int:
		get
	StructIndex as int:
		get
	CallableIndex as int:
		get
	MethodIndex as int:
		get
	FieldIndex as int:
		get
	LiteralIndex as int:
		get
	PropertyIndex as int:
		get
	EventIndex as int:
		get

class InteractiveInterpreterControl(TextEditorControl):

	enum InputState:
		SingleLine = 0
		Block = 1

	class NullCompletionWindowImageProvider(ICompletionWindowImageProvider):

		public static final Instance = NullCompletionWindowImageProvider()

		[getter(ImageList)]
		_imageList = System.Windows.Forms.ImageList()

		NamespaceIndex as int:
			get:
				return 0
		ClassIndex as int:
			get:
				return 0
		InterfaceIndex as int:
			get:
				return 0
		EnumIndex as int:
			get:
				return 0
		StructIndex as int:
			get:
				return 0
		CallableIndex as int:
			get:
				return 0
		MethodIndex as int:
			get:
				return 0
		FieldIndex as int:
			get:
				return 0
		LiteralIndex as int:
			get:
				return 0
		PropertyIndex as int:
			get:
				return 0
		EventIndex as int:
			get:
				return 0

	class LineHistory:

		_lines = []
		_current = 0

		event CurrentLineChanged as EventHandler

		def Add([required] line as string):
			if len(line) > 0 and line != LastLine:
				_lines.Add(line)
			_current = len(_lines)

		LastLine as string:
			get:
				return null if 0 == len(_lines)
				return _lines[-1]

		CurrentLine as string:
			get:
				return null if 0 == len(_lines)
				return _lines[_current]

		def Up():
			MoveTo(_current - 1)

		def Down():
			MoveTo(_current + 1)

		def MoveTo(index as int):
			return if 0 == len(_lines)
			old = _current
			_current = index % len(_lines)
			if old != _current:
				CurrentLineChanged(self, EventArgs.Empty)

	_state = InputState.SingleLine

	_block = System.IO.StringWriter()

	[getter(Interpreter)]
	_interpreter as Boo.Lang.Interpreter.InteractiveInterpreter

	_codeCompletionWindow as CodeCompletionWindow

	[property(CompletionWindowImageProvider, value is not null)]
	_imageProvider as ICompletionWindowImageProvider = NullCompletionWindowImageProvider()

	_lineHistory as LineHistory

	// HACK: when the completion window is shown through CTRL+SPACE
	// it behaves very strangely, the best we can do right now is
	// to prevent the user from typing
	_blockKeys = false

	def constructor():
		self._interpreter = Boo.Lang.Interpreter.InteractiveInterpreter(
								RememberLastValue: true,
								Print: self.print)
		self._interpreter.SetValue("cls", cls)
		self._lineHistory = LineHistory(CurrentLineChanged: _lineHistory_CurrentLineChanged)
		self.Document.HighlightingStrategy = GetBooHighlighting()
		self.EnableFolding =  false
		self.ShowLineNumbers =  false
		self.ShowSpaces = false
		self.ShowTabs =  true
		self.ShowEOLMarkers = false
		self.AllowCaretBeyondEOL = false
		self.ShowInvalidLines = false
		self.Dock = DockStyle.Fill

	CaretColumn:
		get:
			return self.ActiveTextAreaControl.Caret.Column

	CurrentLineText:
		get:
			segment = GetLastLineSegment()
			return self.Document.GetText(segment)[4:]

	override def OnLoad(args as EventArgs):
		super(args)
		prompt()

	def Eval(code as string):
		try:
			_interpreter.LoopEval(code)
		ensure:
			_state = InputState.SingleLine

	private def ConsumeCurrentLine():
		text as string = CurrentLineText # was accessing Control.text member
		_lineHistory.Add(text)
		print("")
		return text

	private def GetLastLineSegment():
		return self.Document.GetLineSegment(self.Document.LineSegmentCollection.Count)

	private def SingleLineInputState():
		code = ConsumeCurrentLine()
		if code[-1:] in ":", "\\":
			_state = InputState.Block
			_block.GetStringBuilder().Length = 0
			_block.WriteLine(code)
		else:
			Eval(code)

	private def BlockInputState():
		code = ConsumeCurrentLine()
		if 0 == len(code):
			Eval(_block.ToString())
		else:
			_block.WriteLine(code)

	def print(msg):
		AppendText("${msg}\r\n")

	def prompt():
		AppendText((">>> ", "... ")[_state])

	def ClearLine():
		segment = GetLastLineSegment()
		self.Document.Replace(segment.Offset + 4,
			self.CurrentLineText.Length,
			"")

	def AppendText(text as string):
		segment = GetLastLineSegment()
		self.Document.Insert(segment.Offset + segment.TotalLength, text)
		MoveCaretToEnd()

	def MoveCaretToEnd():
		segment = GetLastLineSegment()
		newOffset = segment.Offset + segment.TotalLength
		MoveCaretToOffset(newOffset)

	def MoveCaretToOffset(offset as int):
		self.ActiveTextAreaControl.Caret.Position = self.Document.OffsetToPosition(offset)

	override def InitializeTextAreaControl(newControl as TextAreaControl):
		super(newControl)
		newControl.TextArea.DoProcessDialogKey += HandleDialogKey
		newControl.TextArea.KeyEventHandler += HandleKeyPress

	InCodeCompletion:
		get:
			return _codeCompletionWindow is not null and not _codeCompletionWindow.IsDisposed

	private def DotComplete(ch as System.Char):
		ShowCompletionWindow(
			CodeCompletionDataProvider(_imageProvider, GetSuggestions()),
			ch)

	private def ShowCompletionWindow(completionDataProvider, ch as System.Char):
		_codeCompletionWindow = CodeCompletionWindow.ShowCompletionWindow(
					self.ParentForm,
					self,
					"<code>",
					completionDataProvider,
					ch)
		if _codeCompletionWindow is not null:
			_codeCompletionWindow.Closed += def():
				_blockKeys = false

	private def CtrlSpaceComplete():
		_blockKeys = true
		ShowCompletionWindow(
			GlobalsCompletionDataProvider(_imageProvider, self._interpreter),
			Char.MinValue)

	private def GetSuggestions():
		code = CurrentLineText.Insert(self.CaretColumn-4, ".__codecomplete__")
		code = code.Insert(0, _block.ToString()) if InputState.Block == _state
		suggestion = _interpreter.SuggestCodeCompletion(code) as INamespace
		return array(IEntity, 0) if suggestion is null
		return GetChildNamespaces(suggestion) if code.StartsWith("import ")
		return TypeSystemServices.GetAllMembers(suggestion)

	private def GetChildNamespaces(parent as INamespace):
		return array(member
					for member in parent.GetMembers()
					if member.EntityType == EntityType.Namespace)

	private def HandleDialogKey(key as Keys):
		return false if InCodeCompletion

		if key == Keys.Enter:
			try:
				(SingleLineInputState, BlockInputState)[_state]()
			except x:
				print(x)
			prompt()
			return true

		if key == Keys.Up:
			_lineHistory.Up()
			return true
		if key == Keys.Down:
			_lineHistory.Down()
			return true

		if key == (Keys.Control | Keys.Space):
			CtrlSpaceComplete()
			return true

		if key in Keys.Home, Keys.Shift|Keys.Home, Keys.Control|Keys.Home:
			MoveCaretToOffset(GetLastLineSegment().Offset + 4)
			return true

		if key == Keys.Escape:
			ClearLine()
			return true

		if key in Keys.Back, Keys.Left:
			if self.CaretColumn < 5:
				return true
		else:
			if self.CaretColumn < 4:
				MoveCaretToEnd()

		return false

	private def HandleKeyPress(ch as System.Char) as bool:
		return true if _blockKeys

		if InCodeCompletion:
			_codeCompletionWindow.ProcessKeyEvent(ch)

		if ch == "."[0]:
			DotComplete(ch)

		return false

	private def cls():
		self.Document.TextContent = ""
		self.ActiveTextAreaControl.Refresh()

	private def _lineHistory_CurrentLineChanged():
		segment = GetLastLineSegment()
		self.Document.Replace(segment.Offset + 4,
			self.CurrentLineText.Length,
			_lineHistory.CurrentLine)

	def GetBooHighlighting():
		return HighlightingManager.Manager.FindHighlighter("Boo")

	static def InstallDefaultSyntaxModeProvider():
		HighlightingManager.Manager.AddSyntaxModeFileProvider(
			FileSyntaxModeProvider(Path.GetDirectoryName(Application.ExecutablePath)))

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

"""
Interactive Forms-based Console
"""
namespace booish.gui

import System
import System.Drawing
import System.IO
import System.Windows.Forms
import ICSharpCode.TextEditor
import ICSharpCode.TextEditor.Document
import ICSharpCode.TextEditor.Actions
import ICSharpCode.TextEditor.Gui.CompletionWindow
import Boo.Lang.Compiler.TypeSystem

interface ICompletionWindowImageProvider:
	ImageList as ImageList:
		get
	NamespaceIndex as int:
		get
	ClassIndex as int:
		get
	InterfaceIndex as int:
		get
	EnumIndex as int:
		get
	StructIndex as int:
		get
	CallableIndex as int:
		get
	MethodIndex as int:
		get
	FieldIndex as int:
		get
	LiteralIndex as int:
		get
	PropertyIndex as int:
		get
	EventIndex as int:
		get

class InteractiveInterpreterControl(TextEditorControl):

	enum InputState:
		SingleLine = 0
		Block = 1

	class NullCompletionWindowImageProvider(ICompletionWindowImageProvider):

		public static final Instance = NullCompletionWindowImageProvider()

		[getter(ImageList)]
		_imageList = System.Windows.Forms.ImageList()

		NamespaceIndex as int:
			get:
				return 0
		ClassIndex as int:
			get:
				return 0
		InterfaceIndex as int:
			get:
				return 0
		EnumIndex as int:
			get:
				return 0
		StructIndex as int:
			get:
				return 0
		CallableIndex as int:
			get:
				return 0
		MethodIndex as int:
			get:
				return 0
		FieldIndex as int:
			get:
				return 0
		LiteralIndex as int:
			get:
				return 0
		PropertyIndex as int:
			get:
				return 0
		EventIndex as int:
			get:
				return 0

	class LineHistory:

		_lines = []
		_current = 0

		event CurrentLineChanged as EventHandler

		def Add([required] line as string):
			if len(line) > 0 and line != LastLine:
				_lines.Add(line)
			_current = len(_lines)

		LastLine as string:
			get:
				return null if 0 == len(_lines)
				return _lines[-1]

		CurrentLine as string:
			get:
				return null if 0 == len(_lines)
				return _lines[_current]

		def Up():
			MoveTo(_current - 1)

		def Down():
			MoveTo(_current + 1)

		def MoveTo(index as int):
			return if 0 == len(_lines)
			old = _current
			_current = index % len(_lines)
			if old != _current:
				CurrentLineChanged(self, EventArgs.Empty)

	_state = InputState.SingleLine

	_block = System.IO.StringWriter()

	[getter(Interpreter)]
	_interpreter as Boo.Lang.Interpreter.InteractiveInterpreter

	_codeCompletionWindow as CodeCompletionWindow

	[property(CompletionWindowImageProvider, value is not null)]
	_imageProvider as ICompletionWindowImageProvider = NullCompletionWindowImageProvider()

	_lineHistory as LineHistory

	// HACK: when the completion window is shown through CTRL+SPACE
	// it behaves very strangely, the best we can do right now is
	// to prevent the user from typing
	_blockKeys = false

	def constructor():
		self._interpreter = Boo.Lang.Interpreter.InteractiveInterpreter(
								RememberLastValue: true,
								Print: self.print)
		self._interpreter.SetValue("cls", cls)
		self._interpreter.SetValue("exec", exec)
		self._lineHistory = LineHistory(CurrentLineChanged: _lineHistory_CurrentLineChanged)
		self.Document.HighlightingStrategy = GetBooHighlighting()
		self.EnableFolding =  false
		self.ShowLineNumbers =  false
		self.ShowSpaces = false
		self.ShowTabs =  true
		self.ShowEOLMarkers = false
		self.AllowCaretBeyondEOL = false
		self.ShowInvalidLines = false
		self.Dock = DockStyle.Fill

	CaretColumn:
		get:
			return self.ActiveTextAreaControl.Caret.Column

	CurrentLineText:
		get:
			segment = GetLastLineSegment()
			return self.Document.GetText(segment)[4:]

	override def OnLoad(args as EventArgs):
		super(args)
		prompt()

	def Eval(code as string):
		try:
			_interpreter.LoopEval(code)
		ensure:
			_state = InputState.SingleLine

	private def ConsumeCurrentLine():
		text as string = CurrentLineText # was accessing Control.text member
		_lineHistory.Add(text)
		print("")
		return text

	private def GetLastLineSegment():
		return self.Document.GetLineSegment(self.Document.LineSegmentCollection.Count)

	private def SingleLineInputState():
		code = ConsumeCurrentLine()
		if code[-1:] in ":", "\\":
			_state = InputState.Block
			_block.GetStringBuilder().Length = 0
			_block.WriteLine(code)
		else:
			Eval(code)

	private def BlockInputState():
		code = ConsumeCurrentLine()
		if 0 == len(code):
			Eval(_block.ToString())
		else:
			_block.WriteLine(code)

	def print(msg):
		AppendText("${msg}\r\n")

	def prompt():
		AppendText((">>> ", "... ")[_state])

	def ClearLine():
		segment = GetLastLineSegment()
		self.Document.Replace(segment.Offset + 4,
			self.CurrentLineText.Length,
			"")

	def AppendText(text as string):
		segment = GetLastLineSegment()
		self.Document.Insert(segment.Offset + segment.TotalLength, text)
		MoveCaretToEnd()

	def MoveCaretToEnd():
		segment = GetLastLineSegment()
		newOffset = segment.Offset + segment.TotalLength
		MoveCaretToOffset(newOffset)

	def MoveCaretToOffset(offset as int):
		self.ActiveTextAreaControl.Caret.Position = self.Document.OffsetToPosition(offset)

	override def InitializeTextAreaControl(newControl as TextAreaControl):
		super(newControl)
		newControl.TextArea.DoProcessDialogKey += HandleDialogKey
		newControl.TextArea.KeyEventHandler += HandleKeyPress

	InCodeCompletion:
		get:
			return _codeCompletionWindow is not null and not _codeCompletionWindow.IsDisposed

	private def DotComplete(ch as System.Char):
		ShowCompletionWindow(
			CodeCompletionDataProvider(_imageProvider, GetSuggestions()),
			ch)

	private def ShowCompletionWindow(completionDataProvider, ch as System.Char):
		_codeCompletionWindow = CodeCompletionWindow.ShowCompletionWindow(
					self.ParentForm,
					self,
					"<code>",
					completionDataProvider,
					ch)
		if _codeCompletionWindow is not null:
			_codeCompletionWindow.Closed += def():
				_blockKeys = false

	private def CtrlSpaceComplete():
		_blockKeys = true
		ShowCompletionWindow(
			GlobalsCompletionDataProvider(_imageProvider, self._interpreter),
			Char.MinValue)

	private def GetSuggestions():
		code = CurrentLineText.Insert(self.CaretColumn-4, ".__codecomplete__")
		code = code.Insert(0, _block.ToString()) if InputState.Block == _state
		suggestion = _interpreter.SuggestCodeCompletion(code) as INamespace
		return array(IEntity, 0) if suggestion is null
		return GetChildNamespaces(suggestion) if code.StartsWith("import ")
		return TypeSystemServices.GetAllMembers(suggestion)

	private def GetChildNamespaces(parent as INamespace):
		return array(member
					for member in parent.GetMembers()
					if member.EntityType == EntityType.Namespace)

	private def HandleDialogKey(key as Keys):
		return false if InCodeCompletion

		if key == Keys.Enter:
			try:
				(SingleLineInputState, BlockInputState)[_state]()
			except x:
				print(x)
			prompt()
			return true

		if key == Keys.Up:
			_lineHistory.Up()
			return true
		if key == Keys.Down:
			_lineHistory.Down()
			return true

		if key == (Keys.Control | Keys.Space):
			CtrlSpaceComplete()
			return true

		if key in Keys.Home, Keys.Shift|Keys.Home, Keys.Control|Keys.Home:
			MoveCaretToOffset(GetLastLineSegment().Offset + 4)
			return true

		if key == Keys.Escape:
			ClearLine()
			return true

		if key in Keys.Back, Keys.Left:
			if self.CaretColumn < 5:
				return true
		else:
			if self.CaretColumn < 4:
				MoveCaretToEnd()

		return false

	private def HandleKeyPress(ch as System.Char) as bool:
		return true if _blockKeys

		if InCodeCompletion:
			_codeCompletionWindow.ProcessKeyEvent(ch)

		if ch == "."[0]:
			DotComplete(ch)

		return false

	private def cls():
		self.Document.TextContent = ""
		self.ActiveTextAreaControl.Refresh()

	private def exec(scriptName as string):
		_interpreter.Eval(Boo.IO.TextFile.ReadFile(scriptName))

	private def _lineHistory_CurrentLineChanged():
		segment = GetLastLineSegment()
		self.Document.Replace(segment.Offset + 4,
			self.CurrentLineText.Length,
			_lineHistory.CurrentLine)

	def GetBooHighlighting():
		return HighlightingManager.Manager.FindHighlighter("Boo")

	static def InstallDefaultSyntaxModeProvider():
		HighlightingManager.Manager.AddSyntaxModeFileProvider(
			FileSyntaxModeProvider(Path.GetDirectoryName(Application.ExecutablePath)))


CompileToFile

CompileToFile

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

namespace BooTemplate

import Boo.Lang.Compiler

class TemplateCompiler:

	[property(TemplateClassName, value is not null and len(value) > 0)]
	_className = "Template"

	[property(TemplateBaseClass, ValidateBaseClass(value))]
	_baseClass = AbstractTemplate

	def CompileFile([required] fname as string):
		return Compile(Boo.Lang.Compiler.IO.FileInput(fname))

	def Compile([required] input as ICompilerInput):
		compiler = BooCompiler()
		compiler.Parameters.Input.Add(input)
		compiler.Parameters.OutputType = CompilerOutputType.Library

		pipeline = Pipelines.CompileToMemory()
		pipeline[0] = WSABoo.Parser.WSABooParsingStep()
		pipeline.Insert(0, TemplatePreProcessor())
		pipeline.InsertAfter(
				Steps.InitializeTypeSystemServices,
				ApplyTemplateSemantics(self))
		compiler.Parameters.Pipeline = pipeline

		return compiler.Run()

	private def ValidateBaseClass(type as System.Type):
		assert type is not null
		assert ITemplate in type.GetInterfaces()
		assert not type.IsSealed
		return true

namespace BooTemplate

import Boo.Lang.Compiler

class TemplateCompiler:

	[property(TemplateClassName, value is not null and len(value) > 0)]
	_className = "Template"

	[property(TemplateBaseClass, ValidateBaseClass(value))]
	_baseClass = AbstractTemplate

	def Compile([required] input as ICompilerInput):
		compiler = BooCompiler()
		compiler.Parameters.Input.Add(input)
		compiler.Parameters.OutputType = CompilerOutputType.Library

		pipeline = Pipelines.CompileToMemory()
		pipeline[0] = WSABoo.Parser.WSABooParsingStep()
		pipeline.Insert(0, TemplatePreProcessor())
		pipeline.InsertAfter(
				Steps.InitializeTypeSystemServices,
				ApplyTemplateSemantics(self))
		compiler.Parameters.Pipeline = pipeline

		return compiler.Run()

	private def ValidateBaseClass(type as System.Type):
		assert type is not null
		assert ITemplate in type.GetInterfaces()
		assert not type.IsSealed
		return true


len() is more idiomatic

len() is more idiomatic

namespace Boojay.Compilation.Tests

import System
import System.IO
import NUnit.Framework

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.TypeSystem.Services

import Boojay.Compilation.TypeSystem

[TestFixture]
class JarTypeSystemProviderTest(TestWithCompilerContext):

	_jar as string
	_jarWithNamespace as string
	_jarWithComplexNamespace as string

	_subject as JarTypeSystemProvider

	[SetUp]
	override def SetUp():
		super()

		code = [|
			import java.lang

			class Foo:
				def getName():
					return "Bar"
		|]

		codeWithNamespace = [|
			namespace Foo

			import java.lang

			class Bar:
				def getName():
					return "Baz"
		|]

		codeWithComplexNamespace = [|
			namespace Foo.More

			import java.lang

			class Bar:
				def getName():
					return "Baz"
		|]

		_jar = GenerateTempJarWith(code)
		_jarWithNamespace = GenerateTempJarWith(codeWithNamespace)
		_jarWithComplexNamespace = GenerateTempJarWith(codeWithComplexNamespace)

		_subject = JarTypeSystemProvider()

	[Test]
	def ClassName():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			foo = ResolveType(compileUnit, "Foo")
			Assert.AreEqual("Foo", foo.Name)

	[Test]
	def ClassNameInNamespace():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jarWithNamespace)
			bar = ResolveType(compileUnit, "Foo.Bar")
			Assert.AreEqual("Bar", bar.Name)
			Assert.AreEqual("Foo.Bar", bar.FullName)

	[Test]
	def ClassNameInComplexNamespace():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jarWithComplexNamespace)
			bar = ResolveType(compileUnit, "Foo.More.Bar")
			Assert.AreEqual("Bar", bar.Name)
			Assert.AreEqual("Foo.More.Bar", bar.FullName)

	[Test]
	def ClassesAreCached():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			resolveFoo = { ResolveType(compileUnit, "Foo") }
			Assert.AreSame(resolveFoo(), resolveFoo())

	[Test]
	def SimpleConstructor():
		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			foo = ResolveType(compileUnit, "Foo")
			Assert.AreEqual(1, len(foo.GetConstructors()))
			ctor = foo.GetConstructors()[0]
			Assert.AreEqual(0, len(ctor.GetParameters()))

	[Test]
	def ParameterlessInstanceMethod():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			getName as IMethod = ResolveQualifiedName(compileUnit, "Foo.getName")
			Assert.AreEqual(EntityType.Method, getName.EntityType)
			Assert.AreEqual("getName", getName.Name)
			Assert.AreEqual("Foo.getName", getName.FullName)
			Assert.AreSame(ResolveType(compileUnit, "Foo"), getName.DeclaringType)
			Assert.AreEqual(0, getName.GetParameters().Length)

	def ResolveType(compileUnit as ICompileUnit, typeName as string) as IType:
		return ResolveQualifiedName(compileUnit, typeName)

	def ResolveQualifiedName(compileUnit as ICompileUnit, typeName as string):
		return my(NameResolutionService).ResolveQualifiedName(compileUnit.RootNamespace, typeName)

	def GenerateTempJarWith(code as Module):
		jar = Path.GetTempFileName()
		compile(CompileUnit(code))
		GenerateJar(jar, "${type.FullName.Replace('.', '/')}.class" for type in code.Members)
		return jar

namespace Boojay.Compilation.Tests

import System
import System.IO
import NUnit.Framework

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.TypeSystem.Services

import Boojay.Compilation.TypeSystem

[TestFixture]
class JarTypeSystemProviderTest(TestWithCompilerContext):

	_jar as string
	_jarWithNamespace as string
	_jarWithComplexNamespace as string

	_subject as JarTypeSystemProvider

	[SetUp]
	override def SetUp():
		super()

		code = [|
			import java.lang

			class Foo:
				def getName():
					return "Bar"
		|]

		codeWithNamespace = [|
			namespace Foo

			import java.lang

			class Bar:
				def getName():
					return "Baz"
		|]

		codeWithComplexNamespace = [|
			namespace Foo.More

			import java.lang

			class Bar:
				def getName():
					return "Baz"
		|]

		_jar = GenerateTempJarWith(code)
		_jarWithNamespace = GenerateTempJarWith(codeWithNamespace)
		_jarWithComplexNamespace = GenerateTempJarWith(codeWithComplexNamespace)

		_subject = JarTypeSystemProvider()

	[Test]
	def ClassName():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			foo = ResolveType(compileUnit, "Foo")
			Assert.AreEqual("Foo", foo.Name)

	[Test]
	def ClassNameInNamespace():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jarWithNamespace)
			bar = ResolveType(compileUnit, "Foo.Bar")
			Assert.AreEqual("Bar", bar.Name)
			Assert.AreEqual("Foo.Bar", bar.FullName)

	[Test]
	def ClassNameInComplexNamespace():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jarWithComplexNamespace)
			bar = ResolveType(compileUnit, "Foo.More.Bar")
			Assert.AreEqual("Bar", bar.Name)
			Assert.AreEqual("Foo.More.Bar", bar.FullName)

	[Test]
	def ClassesAreCached():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			resolveFoo = { ResolveType(compileUnit, "Foo") }
			Assert.AreSame(resolveFoo(), resolveFoo())

	[Test]
	def SimpleConstructor():
		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			foo = ResolveType(compileUnit, "Foo")
			Assert.AreEqual(1, foo.GetConstructors().Length)
			ctor = foo.GetConstructors()[0]
			Assert.AreEqual(0, ctor.GetParameters().Length)

	[Test]
	def ParameterlessInstanceMethod():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			getName as IMethod = ResolveQualifiedName(compileUnit, "Foo.getName")
			Assert.AreEqual(EntityType.Method, getName.EntityType)
			Assert.AreEqual("getName", getName.Name)
			Assert.AreEqual("Foo.getName", getName.FullName)
			Assert.AreSame(ResolveType(compileUnit, "Foo"), getName.DeclaringType)
			Assert.AreEqual(0, getName.GetParameters().Length)

	def ResolveType(compileUnit as ICompileUnit, typeName as string) as IType:
		return ResolveQualifiedName(compileUnit, typeName)

	def ResolveQualifiedName(compileUnit as ICompileUnit, typeName as string):
		return my(NameResolutionService).ResolveQualifiedName(compileUnit.RootNamespace, typeName)

	def GenerateTempJarWith(code as Module):
		jar = Path.GetTempFileName()
		compile(CompileUnit(code))
		GenerateJar(jar, "${type.FullName.Replace('.', '/')}.class" for type in code.Members)
		return jar


BOO-990: Allow testcases to be ignored.

BOO-990: Allow testcases to be ignored.

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

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

import System
import System.IO
import Boo.Lang.Compiler.Ast.Visitors
import Boo.Lang.Parser

class Util:
	public static argv as (string)

def PortParserTestCases():
"""
Generates WSA parser test cases from
normal parser test cases.
"""
	for testcase in Directory.GetFiles("testcases/parser/roundtrip", "*.boo"):
		if not testcase.EndsWith(".boo"): continue

		fname = Path.GetFileName(testcase)
		wsaTestCase = Path.Combine("testcases/parser/wsa", fname)
		if not File.Exists(wsaTestCase):
			PortParserTestCase(testcase, wsaTestCase)
			print fname

def CopyDocstring(fname as string, writer as TextWriter):
	using file=File.OpenText(fname):
		tripleQuoteCount = 0
		for line in file:
			writer.WriteLine(line)
			if line.Trim() == '"""':
				++tripleQuoteCount
				break if tripleQuoteCount == 2

def PortParserTestCase(fromTestCase as string, toTestCase as string):
	using writer = StreamWriter(toTestCase):
		CopyDocstring(fromTestCase, writer)
		module=BooParser.ParseFile(fromTestCase).Modules[0]
		module.Accept(BooPrinterVisitor(writer, BooPrinterVisitor.PrintOptions.WSA))

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

def MapPath(path):
#	return Path.Combine(Project.BaseDirectory, path)
	return Path.GetFullPath(path)

def WriteTestCases(writer as TextWriter, baseDir as string):
	count, ignored = 0, 0
	for fname as string in Directory.GetFiles(MapPath("testcases/${baseDir}")):
		continue unless fname.EndsWith(".boo")
		ignore = false
		message = ''
		using file = File.OpenText(fname):
			while firstLine = file.ReadLine().Trim():
				break unless firstLine.StartsWith('#')
				if firstLine.StartsWith('#ignore', StringComparison.InvariantCultureIgnoreCase):
					message += ' ' + (firstLine[8:] if len(firstLine) > 9 else '').Trim()
					ignore = true
		++count unless ignore
		++ignored if ignore
		attribute = ("[Ignore(\"${message}\")]" if ignore else '')
		writer.Write("""
		${attribute}[Test]
		public void ${GetTestCaseName(fname)}()
		{
			RunCompilerTestCase(@"${NormalizePath(Path.GetFileName(fname))}");
		}
		""")
	print("{0,5} {1,7}  {2}" % (count, ignored, baseDir))

def GenerateTestFixture(srcDir as string, targetFile as string, fixtureAssembly as string, header as string):
	return if Util.argv and len(Util.argv) and Util.argv[0] == fixtureAssembly
	using writer=StreamWriter(MapPath(targetFile)):
		writer.Write(header)
		WriteTestCases(writer, srcDir)
		writer.Write("""

		override protected string GetRelativeTestCasesPath()
		{
			return "${NormalizePath(srcDir)}";
		}
	}
}
""")

def NormalizePath(path as string):
	return path.Replace('\\', '/')

def GenerateIntegrationTestFixtures():
	for dir in Directory.GetDirectories("testcases/integration"):
		if /\.svn/.IsMatch(dir): continue
		GenerateIntegrationTestFixture("integration/${Path.GetFileName(dir)}")

def PascalCase(name as string):
	return name[:1].ToUpper() + name[1:]

def IntegrationTestFixtureName(dir as string):
	baseName = join(PascalCase(part) for part in /-/.Split(Path.GetFileName(dir)), '')
	return "${baseName}IntegrationTestFixture"

def GenerateIntegrationTestFixture(dir as string):
	fixtureName = IntegrationTestFixtureName(dir)
	header = """namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class ${fixtureName} : AbstractCompilerTestCase
	{
	"""
	GenerateTestFixture(dir, "BooCompiler.Tests/${fixtureName}.cs", "BooCompiler.${fixtureName.Replace('TestFixture', '')}", header)

#Util.argv = argv

print("{0,-5} {1,-7}  {2}" % ('tests', 'ignored', 'directory'))

GenerateIntegrationTestFixtures()

GenerateTestFixture("regression", "BooCompiler.Tests/RegressionTestFixture.cs", "BooCompiler.Regression", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class RegressionTestFixture : AbstractCompilerTestCase
	{
""")

GenerateTestFixture("errors", "BooCompiler.Tests/CompilerErrorsTestFixture.cs", "BooCompiler.CompilerErrors", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;
	using Boo.Lang.Compiler;

	[TestFixture]
	public class CompilerErrorsTestFixture : AbstractCompilerErrorsTestFixture
	{
""")

GenerateTestFixture("warnings", "BooCompiler.Tests/CompilerWarningsTestFixture.cs", "BooCompiler.CompilerWarnings", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;
	using Boo.Lang.Compiler;

	[TestFixture]
	public class CompilerWarningsTestFixture : AbstractCompilerTestCase
	{
		protected override CompilerPipeline SetUpCompilerPipeline()
		{
			CompilerPipeline pipeline = new Boo.Lang.Compiler.Pipelines.Compile();
			pipeline.Add(new Boo.Lang.Compiler.Steps.PrintWarnings());
			return pipeline;
		}
""")

GenerateTestFixture("macros", "BooCompiler.Tests/MacrosTestFixture.cs", "BooCompiler.Macros", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class MacrosTestFixture : AbstractCompilerTestCase
	{
""")

GenerateTestFixture("stdlib", "BooCompiler.Tests/StdlibTestFixture.cs", "BooCompiler.Stdlib", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class StdlibTestFixture : AbstractCompilerTestCase
	{
""")

GenerateTestFixture("attributes", "BooCompiler.Tests/AttributesTestFixture.cs", "BooCompiler.Attributes", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;
	using Boo.Lang.Compiler;
	using Boo.Lang.Compiler.Steps;

	[TestFixture]
	public class AttributesTestFixture : AbstractCompilerTestCase
	{
		override protected CompilerPipeline SetUpCompilerPipeline()
		{
			CompilerPipeline pipeline = new Boo.Lang.Compiler.Pipelines.Parse();
			pipeline.Add(new InitializeTypeSystemServices());
			pipeline.Add(new InitializeNameResolutionService());
			pipeline.Add(new IntroduceGlobalNamespaces());
			pipeline.Add(new BindNamespaces());
			pipeline.Add(new BindAndApplyAttributes());
			pipeline.Add(new PrintBoo());
			return pipeline;
		}
""")

GenerateTestFixture("parser/roundtrip", "build/ParserRoundtripTestFixture.cs", "Boo.Lang.Parser", """
namespace Boo.Lang.Parser.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class ParserRoundtripTestFixture : AbstractParserTestFixture
	{
		void RunCompilerTestCase(string fname)
		{
			RunParserTestCase(fname);
		}
""")

PortParserTestCases()
GenerateTestFixture("parser/wsa", "build/WSAParserRoundtripTestFixture.cs", "Boo.Lang.Parser", """
namespace Boo.Lang.Parser.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class WSAParserRoundtripTestFixture : AbstractWSAParserTestFixture
	{
		void RunCompilerTestCase(string fname)
		{
			RunParserTestCase(fname);
		}
""")

GenerateTestFixture("semantics", "BooCompiler.Tests/SemanticsTestFixture.cs", "BooCompiler.Semantics", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;
	using Boo.Lang.Compiler;
	using Boo.Lang.Compiler.Pipelines;

	[TestFixture]
	public class SemanticsTestFixture : AbstractCompilerTestCase
	{
		protected override CompilerPipeline SetUpCompilerPipeline()
		{
			return new CompileToBoo();
		}
""")

GenerateTestFixture("ducky", "BooCompiler.Tests/DuckyTestFixture.cs", "BooCompiler.Ducky", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;
	using Boo.Lang.Compiler;
	using Boo.Lang.Compiler.Pipelines;

	[TestFixture]
	public class DuckyTestFixture : AbstractCompilerTestCase
	{
		protected override void CustomizeCompilerParameters()
		{
			_parameters.Ducky = true;
		}
""")

GenerateTestFixture("net2/generics", "BooCompiler.Tests/GenericsTestFixture.cs", "BooCompiler.Generics", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class GenericsTestFixture : AbstractCompilerTestCase
	{
		override protected void RunCompilerTestCase(string name)
		{
			if (System.Environment.Version.Major < 2) Assert.Ignore("Test requires .net 2.");
			System.ResolveEventHandler resolver = InstallAssemblyResolver(BaseTestCasesPath);
			try
			{
				base.RunCompilerTestCase(name);
			}
			finally
			{
				RemoveAssemblyResolver(resolver);
			}
		}

		override protected void CopyDependencies()
		{
			CopyAssembliesFromTestCasePath();
		}
""")

GenerateTestFixture("net2/errors", "BooCompiler.Tests/Net2ErrorsTestFixture.cs", "BooCompiler.Net2Errors", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class Net2ErrorsTestFixture : AbstractCompilerErrorsTestFixture
	{
		override protected void RunCompilerTestCase(string name)
		{
			if (System.Environment.Version.Major < 2) Assert.Ignore("Test requires .net 2.");
			base.RunCompilerTestCase(name);
		}
""")

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

import System
import System.IO
import Boo.Lang.Compiler.Ast.Visitors
import Boo.Lang.Parser

def PortParserTestCases():
"""
Generates WSA parser test cases from
normal parser test cases.
"""
	for testcase in Directory.GetFiles("testcases/parser/roundtrip", "*.boo"):
		if not testcase.EndsWith(".boo"): continue

		fname = Path.GetFileName(testcase)
		wsaTestCase = Path.Combine("testcases/parser/wsa", fname)
		if not File.Exists(wsaTestCase):
			PortParserTestCase(testcase, wsaTestCase)
			print fname

def CopyDocstring(fname as string, writer as TextWriter):
	using file=File.OpenText(fname):
		tripleQuoteCount = 0
		for line in file:
			writer.WriteLine(line)
			if line.Trim() == '"""':
				++tripleQuoteCount
				break if tripleQuoteCount == 2

def PortParserTestCase(fromTestCase as string, toTestCase as string):
	using writer = StreamWriter(toTestCase):
		CopyDocstring(fromTestCase, writer)
		module=BooParser.ParseFile(fromTestCase).Modules[0]
		module.Accept(BooPrinterVisitor(writer, BooPrinterVisitor.PrintOptions.WSA))

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

def MapPath(path):
#	return Path.Combine(Project.BaseDirectory, path)
	return Path.GetFullPath(path)

def WriteTestCases(writer as TextWriter, baseDir as string):
	count = 0
	for fname as string in Directory.GetFiles(MapPath("testcases/${baseDir}")):
		continue unless fname.EndsWith(".boo")
		++count
		writer.Write("""
		[Test]
		public void ${GetTestCaseName(fname)}()
		{
			RunCompilerTestCase(@"${NormalizePath(Path.GetFileName(fname))}");
		}
		""")
	print("${count} test cases found in ${baseDir}.")

def GenerateTestFixture(srcDir as string, targetFile as string, header as string):
	using writer=StreamWriter(MapPath(targetFile)):
		writer.Write(header)
		WriteTestCases(writer, srcDir)
		writer.Write("""

		override protected string GetRelativeTestCasesPath()
		{
			return "${NormalizePath(srcDir)}";
		}
	}
}
""")

def NormalizePath(path as string):
	return path.Replace('\\', '/')

def GenerateIntegrationTestFixtures():
	for dir in Directory.GetDirectories("testcases/integration"):
		if /\.svn/.IsMatch(dir): continue
		GenerateIntegrationTestFixture("integration/${Path.GetFileName(dir)}")

def PascalCase(name as string):
	return name[:1].ToUpper() + name[1:]

def IntegrationTestFixtureName(dir as string):
	baseName = join(PascalCase(part) for part in /-/.Split(Path.GetFileName(dir)), '')
	return "${baseName}IntegrationTestFixture"

def GenerateIntegrationTestFixture(dir as string):
	fixtureName = IntegrationTestFixtureName(dir)
	header = """namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class ${fixtureName} : AbstractCompilerTestCase
	{
	"""
	GenerateTestFixture(dir, "BooCompiler.Tests/${fixtureName}.cs", header)

GenerateIntegrationTestFixtures()

GenerateTestFixture("regression", "BooCompiler.Tests/RegressionTestFixture.cs", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class RegressionTestFixture : AbstractCompilerTestCase
	{
""")

GenerateTestFixture("errors", "BooCompiler.Tests/CompilerErrorsTestFixture.cs", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;
	using Boo.Lang.Compiler;

	[TestFixture]
	public class CompilerErrorsTestFixture : AbstractCompilerErrorsTestFixture
	{
""")

GenerateTestFixture("warnings", "BooCompiler.Tests/CompilerWarningsTestFixture.cs", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;
	using Boo.Lang.Compiler;

	[TestFixture]
	public class CompilerWarningsTestFixture : AbstractCompilerTestCase
	{
		protected override CompilerPipeline SetUpCompilerPipeline()
		{
			CompilerPipeline pipeline = new Boo.Lang.Compiler.Pipelines.Compile();
			pipeline.Add(new Boo.Lang.Compiler.Steps.PrintWarnings());
			return pipeline;
		}
""")

GenerateTestFixture("macros", "BooCompiler.Tests/MacrosTestFixture.cs", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class MacrosTestFixture : AbstractCompilerTestCase
	{
""")

GenerateTestFixture("stdlib", "BooCompiler.Tests/StdlibTestFixture.cs", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class StdlibTestFixture : AbstractCompilerTestCase
	{
""")

GenerateTestFixture("attributes", "BooCompiler.Tests/AttributesTestFixture.cs", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;
	using Boo.Lang.Compiler;
	using Boo.Lang.Compiler.Steps;

	[TestFixture]
	public class AttributesTestFixture : AbstractCompilerTestCase
	{
		override protected CompilerPipeline SetUpCompilerPipeline()
		{
			CompilerPipeline pipeline = new Boo.Lang.Compiler.Pipelines.Parse();
			pipeline.Add(new InitializeTypeSystemServices());
			pipeline.Add(new InitializeNameResolutionService());
			pipeline.Add(new IntroduceGlobalNamespaces());
			pipeline.Add(new BindNamespaces());
			pipeline.Add(new BindAndApplyAttributes());
			pipeline.Add(new PrintBoo());
			return pipeline;
		}
""")

GenerateTestFixture("parser/roundtrip", "build/ParserRoundtripTestFixture.cs", """
namespace Boo.Lang.Parser.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class ParserRoundtripTestFixture : AbstractParserTestFixture
	{
		void RunCompilerTestCase(string fname)
		{
			RunParserTestCase(fname);
		}
""")

PortParserTestCases()
GenerateTestFixture("parser/wsa", "build/WSAParserRoundtripTestFixture.cs", """
namespace Boo.Lang.Parser.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class WSAParserRoundtripTestFixture : AbstractWSAParserTestFixture
	{
		void RunCompilerTestCase(string fname)
		{
			RunParserTestCase(fname);
		}
""")

GenerateTestFixture("semantics", "BooCompiler.Tests/SemanticsTestFixture.cs", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;
	using Boo.Lang.Compiler;
	using Boo.Lang.Compiler.Pipelines;

	[TestFixture]
	public class SemanticsTestFixture : AbstractCompilerTestCase
	{
		protected override CompilerPipeline SetUpCompilerPipeline()
		{
			return new CompileToBoo();
		}
""")

GenerateTestFixture("ducky", "BooCompiler.Tests/DuckyTestFixture.cs", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;
	using Boo.Lang.Compiler;
	using Boo.Lang.Compiler.Pipelines;

	[TestFixture]
	public class DuckyTestFixture : AbstractCompilerTestCase
	{
		protected override void CustomizeCompilerParameters()
		{
			_parameters.Ducky = true;
		}
""")

GenerateTestFixture("net2/generics", "BooCompiler.Tests/GenericsTestFixture.cs", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class GenericsTestFixture : AbstractCompilerTestCase
	{
		override protected void RunCompilerTestCase(string name)
		{
			if (System.Environment.Version.Major < 2) Assert.Ignore("Test requires .net 2.");
			System.ResolveEventHandler resolver = InstallAssemblyResolver(BaseTestCasesPath);
			try
			{
				base.RunCompilerTestCase(name);
			}
			finally
			{
				RemoveAssemblyResolver(resolver);
			}
		}

		override protected void CopyDependencies()
		{
			CopyAssembliesFromTestCasePath();
		}
""")

GenerateTestFixture("net2/errors", "BooCompiler.Tests/Net2ErrorsTestFixture.cs", """
namespace BooCompiler.Tests
{
	using NUnit.Framework;

	[TestFixture]
	public class Net2ErrorsTestFixture : AbstractCompilerErrorsTestFixture
	{
		override protected void RunCompilerTestCase(string name)
		{
			if (System.Environment.Version.Major < 2) Assert.Ignore("Test requires .net 2.");
			base.RunCompilerTestCase(name);
		}
""")


spaces is a simpler name

spaces is a simpler name

namespace pegs

import Boo.Pegs
import System.Collections.Generic

// actions in the peg are just closures
// so they can see whatever variables were introduced
// before the peg definition

stack = Stack[of int]()
push = stack.Push
pop = stack.Pop

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

while true:
	expression = prompt("> ")
	if string.IsNullOrEmpty(expression): break

	ctx = PegContext(expression)
	if calculator.Match(ctx):
		print pop()
	else:
		print "--" + "-" * ctx.Input.Position + "^"
		print "DOES NOT COMPUTE!"

	stack.Clear()

namespace pegs

import Boo.Pegs
import System.Collections.Generic

// actions in the peg are just closures
// so they can see whatever variables were introduced
// before the peg definition

stack = Stack[of int]()
push = stack.Push
pop = stack.Pop

peg:
	calculator = 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 = PegContext(expression)
	if calculator.Match(ctx):
		print pop()
	else:
		print "--" + "-" * ctx.Input.Position + "^"
		print "DOES NOT COMPUTE!"

	stack.Clear()