Assembly.Load(string) instead of Assembly.Load(AssemblyName) which is marked SecurityCritical on the unity profile

namespace UnityScript.Scripting

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

class CompilationErrorsException(Exception):

	[getter(Errors)]
	_errors as CompilerErrorCollection

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

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

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

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

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

class EvaluationScriptCacheKey:

	_contextType as System.Type
	_code as string

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

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

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

class EvaluationScript:

	virtual def Run() as object:
		pass

class Evaluator:

	private static final TaintedAnnotation = object()

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

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

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

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

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

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

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

	private def CompileScript():

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

		type = DoCompile()
		CacheScript(type)
		return type

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

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

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

	private def DoCompile():

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

		AddEvaluationContextReferencesTo(compiler)

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

		#print _compilationResult.CompileUnit.ToCodeString()
		return _compilationResult.GeneratedAssembly.GetType("script")

	private def AddEvaluationContextReferencesTo(compiler as UnityScriptCompiler):
		contextType = _context.GetType()
		if contextType.DeclaringType is null:
			return

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

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

namespace UnityScript.Scripting

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

class CompilationErrorsException(Exception):

	[getter(Errors)]
	_errors as CompilerErrorCollection

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

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

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

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

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

class EvaluationScriptCacheKey:

	_contextType as System.Type
	_code as string

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

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

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

class EvaluationScript:

	virtual def Run() as object:
		pass

class Evaluator:

	private static final TaintedAnnotation = object()

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

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

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

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

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

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

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

	private def CompileScript():

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

		type = DoCompile()
		CacheScript(type)
		return type

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

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

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

	private def DoCompile():

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

		AddEvaluationContextReferencesTo(compiler)

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

		#print _compilationResult.CompileUnit.ToCodeString()
		return _compilationResult.GeneratedAssembly.GetType("script")

	private def AddEvaluationContextReferencesTo(compiler as UnityScriptCompiler):
		contextType = _context.GetType()
		if contextType.DeclaringType is null:
			return

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

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


fixed typo, the intention was to capture stderror

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

class ConsoleCapture(IDisposable):
	_console = StringWriter()
	_oldOut = Console.Out
	_oldError = Console.Error

	def constructor():
		Console.SetOut(_console)
		Console.SetError(_console)

	override def ToString():
		return _console.ToString()

	def Dispose():
		Console.SetOut(_oldOut)
		Console.SetError(_oldError)

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

class ConsoleCapture(IDisposable):
	_console = StringWriter()
	_oldOut = Console.Out
	_oldError = Console.Error

	def constructor():
		Console.SetOut(_console)
		Console.SetOut(_console)

	override def ToString():
		return _console.ToString()

	def Dispose():
		Console.SetOut(_oldOut)
		Console.SetError(_oldError)


boo-0.4.4 interim release

boo-0.4.4 interim release

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

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

import System.Web.Services

[WebService]
class Math:

	[WebMethod]
	def Add(a as int, b as int):
		return a+b

	[WebMethod]
	def Multiply(a as int, b as int):
		return a*b


Fixing try-ensure in async methods

Fixing try-ensure in async methods

"""
Pre
show1
show2
disposed2
disposed1
Post
result
"""

import System.Threading.Tasks
import System

class Program:
    class D(IDisposable):
        public def Dispose():
            print "disposed1"
    class D2(IDisposable):
        public def Dispose():
            print "disposed2"

    [async] static def M(input as int) as Task[of string]:
        print "Pre"
        using window1 = D():
            print "show1"
            using window = D2():
                print "show2"
                for i in range(2):
                    await Task.Delay(100)
        print "Post"
        return "result"

static def Main():
    System.Console.WriteLine(Program.M(0).Result)

"""
Pre
show
show
disposed
disposed
Post
result
"""

import System.Threading.Tasks
import System

class Program:
    class D(IDisposable):
        public def Dispose():
            print "disposed"

    [async] static def M(input as int) as Task[of string]:
        print "Pre"
        using window = D():
            print "show"
            using window = D():
                print "show"
                for i in range(2):
                    await Task.Delay(100)
        print "Post"
        return "result"

static def Main():
    System.Console.WriteLine(Program.M(0).Result)


Removed bug

Removed bug

m = matrix(int, 3, 512, 512)
seed = 42
for i in range(2):
    for j in range(512):
        for k in range(512):
            m[i, j, k] = seed
            seed *= 25189
            seed %= 32749

sum = 0
for i in range(512):
    for j in range(512):
        for k in range(512):
            m[2, i, j] = m[2, i, j] + m[0, i, k] * m[1, k, j]
            m[2, i, j] = m[2, i, j] % 65536
        sum += ((i * j) % 256) * m[2, i, j]
        sum %= 65536
if len(argv) > 0:
    print(sum)

m = matrix(int, 3, 512, 512)
seed = 42
for i in range(2):
    for j in range(512):
        for k in range(512):
            m[i, j, k] = seed
            seed *= 25189
            seed %= 32749

sum = 0
for i in range(512):
    print(i)
    for j in range(512):
        for k in range(512):
            m[2, i, j] = m[2, i, j] + m[0, i, k] * m[1, k, j]
            m[2, i, j] = m[2, i, j] % 65536
        sum += ((i * j) % 256) * m[2, i, j]
        sum %= 65536
if len(argv) > 0:
    print(sum)


trying to resolve ReturnType

trying to resolve ReturnType

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:1] == "L":
			booTypeName = typeName[1:].Replace("/", ".")
			resolvedType = my(NameResolutionService).ResolveQualifiedName(booTypeName)
			raise "ResolveQualifiedName failed to resolve ${booTypeName}" unless resolvedType
			return resolvedType
		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
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)


Updated the unsupported features

Updated the unsupported features

namespace BooJs.Compiler.Steps

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

class UnsupportedFeatures(AbstractVisitorCompilerStep):
"""
    Detect those features not yet supported by Boojs and raise errors for them

    Note: This step should be placed just after parsing and just after expanding macros
"""

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

    def NotImplemented(node, msg):
        Error( CompilerErrorFactory.NotImplemented(node, msg) )

    def OnStructDefinition(node as StructDefinition):
    """ Boo's struct a value type like strings or integers that works as a class. It means
        that when declaring it an instance is created and when passing it to a function a
        copy is made instead of passing a reference.
        Javascript doesn't have any similar type so the conversion is not trivial. Perhaps
        we can have a 'clone' method in the runtime which gets used when we detect a struct
        type.
    """
        NotImplemented node, 'Struct is not implemented in Boojs'

    def OnSlicingExpression(node as SlicingExpression):
    """ Boo implements python style slicing, allowing to extract/replace ranges. JS does not have
        a direct syntax for it thus until we can work on converting the slices we flag this
        feature as unsupported
    """
        if len(node.Indices) != 1:
            NotImplemented node, 'Only one index is supported when slicing'

        slice = node.Indices[0]
        if not slice.Begin or slice.End or slice.Step:
            NotImplemented node, 'Range slicing is not supported'

        if slice.Begin isa UnaryExpression and \
           (slice.Begin as UnaryExpression).Operator == UnaryOperatorType.UnaryNegation:
            NotImplemented node, 'Slicing with a negative index is not supported'

        print slice.Begin, slice.Begin.NodeType

    def OnTimeSpanLiteralExpression(node as TimeSpanLiteralExpression):
    """ Literal timespan values ( 1s, 4d, 3h ...)
    """
        NotImplemented node, 'Timespan expressions are not supported'

    def OnYieldStatement(node as YieldStatement):
    """ Porting yield/generators to standard Javascript is very difficult and it's not
        clear that it could work in all cases. Only Firefox supports them natively thus
        one option could be to add a compiler flag to allow them.
    """
        NotImplemented node, 'Yield is not implemented in Boojs'

    def OnEvent(node as Event):
    """ Boo Event's are a way to easily setup delegates in classes, implementing the
        observer pattern. Basically they allow registering a callback on them from outside
        the class but only firing them from inside the class.
        There is no clear translation of them to Javascript, we could perhaps just implement
        them using a runtime.
    """
        NotImplemented node, 'Event is not implemented in Boojs'

namespace BooJs.Compiler.Steps

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

class UnsupportedFeatures(AbstractVisitorCompilerStep):
"""
    Detect those features not yet supported by Boojs and raise errors for them

    Note: This step should be placed just after parsing and just after expanding macros
"""

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

    def NotImplemented(node, msg):
        Error( CompilerErrorFactory.NotImplemented(node, msg) )

    def OnStructDefinition(node as StructDefinition):
    """ Boo's struct a value type like strings or integers that works as a class. It means
        that when declaring it an instance is created and when passing it to a function a
        copy is made instead of passing a reference.
        Javascript doesn't have any similar type so the conversion is not trivial. Perhaps
        we can have a 'clone' method in the runtime which gets used when we detect a struct
        type.
    """
        NotImplemented node, 'Struct is not implemented in Boojs'

    def OnSlicingExpression(node as SlicingExpression):
    """ Boo implements python style slicing, allowing to extract/replace ranges. JS does not have
        a direct syntax for it thus until we can work on converting the slices we flag this
        feature as unsupported
    """
        if len(node.Indices) != 1:
            NotImplemented node, 'Only one index is supported when slicing'

        slice = node.Indices[0]
        if not slice.Begin or slice.End or slice.Step:
            NotImplemented node, 'Range slicing is not supported'

        if slice.Begin isa UnaryExpression and \
           (slice.Begin as UnaryExpression).Operator == UnaryOperatorType.UnaryNegation:
            NotImplemented node, 'Slicing with a negative index is not supported'

        print slice.Begin, slice.Begin.NodeType

    def _OnUnpackStatement(node as UnpackStatement):
    """ Boo allows to unpack enumerables into local variables: a, b, c = [1, 2, 3]
    """
        NotImplemented node, 'Unpack statements are not supported'

    def OnTimeSpanLiteralExpression(node as TimeSpanLiteralExpression):
    """ Literal timespan values ( 1s, 4d, 3h ...)
    """
        NotImplemented node, 'Timespan expressions are not supported'

    def __OnYieldStatement(node as YieldStatement):
    """ Porting yield/generators to standard Javascript is very difficult and it's not
        clear that it could work in all cases. Only Firefox supports them natively thus
        one option could be to add a compiler flag to allow them.
    """
        NotImplemented node, 'Yield is not implemented in Boojs'

    def OnEvent(node as Event):
    """ Boo Event's are a way to easily setup delegates in classes, implementing the
        observer pattern. Basically they allow registering a callback on them from outside
        the class but only firing them from inside the class.
        There is no clear translation of them to Javascript, we could perhaps just implement
        them using a runtime.
    """
        NotImplemented node, 'Event is not implemented in Boojs'


show runtime version (1.1 or 2.0) in booish

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

import System
import System.Diagnostics
import Boo.Lang.Compiler.Steps
import Boo.Lang.Interpreter

interpreter = InteractiveInterpreter(RememberLastValue: true)

if "--print-modules" in argv:
	interpreter.Pipeline.Add(PrintBoo())

if "--debug" in argv:
	Debug.Listeners.Add(TextWriterTraceListener(Console.Out))

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:
    dir(Type): lists the members of a type
    help(Type): prints detailed information about a type
    load(string): evals an external boo file
    globals(): returns the names of all variables known to the interpreter
	getRootNamespace(): namespace navigation

Enter boo code in the prompt below."""

interpreter.ConsoleLoopEval()

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

import System
import System.Diagnostics
import Boo.Lang.Compiler.Steps
import Boo.Lang.Interpreter

interpreter = InteractiveInterpreter(RememberLastValue: true)

if "--print-modules" in argv:
	interpreter.Pipeline.Add(PrintBoo())

if "--debug" in argv:
	Debug.Listeners.Add(TextWriterTraceListener(Console.Out))

print """Welcome to booish, an interpreter for the boo programming language.

Running boo ${BooVersion}.

The following builtin functions are available:
    dir(Type): lists the members of a type
    help(Type): prints detailed information about a type
    load(string): evals an external boo file
    globals(): returns the names of all variables known to the interpreter
	getRootNamespace(): namespace navigation

Enter boo code in the prompt below."""

interpreter.ConsoleLoopEval()


Fixed small bug with safe access in slicing expressions

namespace BooJs.Compiler.Steps

import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps(AbstractTransformerCompilerStep)

class SafeAccess(AbstractTransformerCompilerStep):
"""
Desugarizes the safe access operator.

  foo?
  (foo is not null)

  foo?.bar?
  ((foo.bar if foo is not null else null) is not null)

  foo?.bar
  (foo.bar if foo != null else null)

  foo?.bar?.baz
  (foo.bar.baz if (foo.bar if foo is not null else null) is not null else null)

  foo?.bar?[2]
  (foo.bar[2] if (foo.bar if foo is not null else null) is not null else null)

  foo?.bar?()
  (foo.bar() if (foo.bar if foo is not null else null) is not null else null)

"""
    override def LeaveUnaryExpression(node as UnaryExpression):
        if node.Operator == UnaryOperatorType.SafeAccess:
            # target references should already be resolved, so just evaluate as existential
            tern = [| $(node.Operand) is not null |]
            ReplaceCurrentNode tern

    override def OnMemberReferenceExpression(node as MemberReferenceExpression):
        tern = ProcessTargets(node)
        if tern:
            ReplaceCurrentNode tern
        else:
            super(node)

    override def OnMethodInvocationExpression(node as MethodInvocationExpression):
        # JavaScript binds the `this` keyword based on the calling reference.
        # Make sure we keep the reference intact if there is a direct safe access: foo.bar?()
        if IsSafeAccess(node.Target):
            ue = node.Target as UnaryExpression
            node.Target = ue.Operand
            tern = [| ($node if $(node.Target) is not null else null) |]
            Visit tern
            ReplaceCurrentNode tern
            return

        tern = ProcessTargets(node)
        if tern:
            Visit node.Arguments
            ReplaceCurrentNode tern
        else:
            super(node)

    override def OnSlicingExpression(node as SlicingExpression):
        tern = ProcessTargets(node)
        if tern:
            Visit node.Indices
            ReplaceCurrentNode tern
        else:
            super(node)

    protected def IsTargetable(node) as bool:
        return node isa MemberReferenceExpression or \
               node isa MethodInvocationExpression or \
               node isa SlicingExpression

    protected def IsSafeAccess(node) as bool:
        return node isa UnaryExpression and (node as UnaryExpression).Operator == UnaryOperatorType.SafeAccess

    protected def ProcessTargets(node as Expression) as Expression:
        # Look for safe access operators in the targets chain
        ue as UnaryExpression
        target as duck = node
        while IsTargetable(target):
            if IsSafeAccess(target.Target):
                ue = target.Target
                break
            target = target.Target

        # No safe access operator was found
        return null if not ue

        # Make sure previous access operators are processed
        Visit(target.Target as Expression)

        # Target the safe access to a temporary variable
        tmp = ReferenceExpression(Context.GetUniqueName('safe'))
        target.Target = tmp
        # Break the targets chain into a ternary operation
        tern = [| ($node if ($tmp = $(ue.Operand)) is not null else null) |]
        return tern

namespace BooJs.Compiler.Steps

import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps(AbstractTransformerCompilerStep)

class SafeAccess(AbstractTransformerCompilerStep):
"""
Desugarizes the safe access operator.

  foo?
  (foo is not null)

  foo?.bar?
  ((foo.bar if foo is not null else null) is not null)

  foo?.bar
  (foo.bar if foo != null else null)

  foo?.bar?.baz
  (foo.bar.baz if (foo.bar if foo is not null else null) is not null else null)

  foo?.bar?[2]
  (foo.bar[2] if (foo.bar if foo is not null else null) is not null else null)

  foo?.bar?()
  (foo.bar() if (foo.bar if foo is not null else null) is not null else null)

"""
    override def LeaveUnaryExpression(node as UnaryExpression):
        if node.Operator == UnaryOperatorType.SafeAccess:
            # target references should already be resolved, so just evaluate as existential
            tern = [| $(node.Operand) is not null |]
            ReplaceCurrentNode tern

    override def OnMemberReferenceExpression(node as MemberReferenceExpression):
        tern = ProcessTargets(node)
        if tern:
            ReplaceCurrentNode tern
        else:
            super(node)

    override def OnMethodInvocationExpression(node as MethodInvocationExpression):
        # JavaScript binds the `this` keyword based on the calling reference.
        # Make sure we keep the reference intact if there is a direct safe access: foo.bar?()
        if IsSafeAccess(node.Target):
            ue = node.Target as UnaryExpression
            node.Target = ue.Operand
            tern = [| ($node if $(node.Target) is not null else null) |]
            Visit tern
            ReplaceCurrentNode tern
            return

        tern = ProcessTargets(node)
        if tern:
            Visit node.Arguments
            ReplaceCurrentNode tern
        else:
            super(node)

    override def OnSlicingExpression(node as SlicingExpression):
        tern = ProcessTargets(node)
        if tern:
            ReplaceCurrentNode tern
        else:
            super(node)

    protected def IsTargetable(node) as bool:
        return node isa MemberReferenceExpression or \
               node isa MethodInvocationExpression or \
               node isa SlicingExpression

    protected def IsSafeAccess(node) as bool:
        return node isa UnaryExpression and (node as UnaryExpression).Operator == UnaryOperatorType.SafeAccess

    protected def ProcessTargets(node as Expression) as Expression:
        # Look for safe access operators in the targets chain
        ue as UnaryExpression
        target as duck = node
        while IsTargetable(target):
            if IsSafeAccess(target.Target):
                ue = target.Target
                break
            target = target.Target

        # No safe access operator was found
        return null if not ue

        # Make sure previous access operators are processed
        Visit(target.Target as Expression)

        # Target the safe access to a temporary variable
        tmp = ReferenceExpression(Context.GetUniqueName('safe'))
        target.Target = tmp
        # Break the targets chain into a ternary operation
        tern = [| ($node if ($tmp = $(ue.Operand)) is not null else null) |]
        return tern


tray icon now displays the current activity

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

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

"""
This example shows how to use db4o 3.0 (http://www.db4o.com), a great
oodbm infrastructure, to implement a simple time tracking application.
"""

namespace TimeTracker

import System
import System.ComponentModel
import System.IO
import System.Drawing
import System.Windows.Forms
import TimeTracker.Model

class MainForm(Form):

	_system as TimeTrackerSystem

	_components = System.ComponentModel.Container()

	_current as Activity

	_tabs = TabControl(Dock: DockStyle.Fill)

	_view = ListView(View: View.Details, Dock: DockStyle.Fill)

	_timer = System.Windows.Forms.Timer(_components,
										Tick: UpdateNotifyText,
										Interval: 30000)

	_notify as NotifyIcon

	def constructor():
		self.Text = "Boo Time Tracker (powered by db4o)"
		self.ShowInTaskbar = false
		self.MinimizeBox = false
		Minimize()

		_notify = NotifyIcon(_components,
				Text: self.Text,
				Icon: self.Icon,
				Visible: true,
				ContextMenu: CreateContextMenu(),
				DoubleClick: { self.WindowState = WindowState.Normal })

		_system = TimeTrackerSystem(
						Path.Combine(
							Application.UserAppDataPath,
							"timetracker.yap"))

		activitiesPage = TabPage(Text: "Activities")
		activitiesPage.Controls.Add(_view)

		prompt = booish.gui.PromptBox(
						Font: System.Drawing.Font("Lucida Console", 11))
		prompt.Interpreter.SetValue("system", _system)
		prompt.Interpreter.SetValue("MainForm", self)
		prompt.Interpreter.References.Add(typeof(Project).Assembly)
		promptPage = TabPage(Text: "Console")
		promptPage.Controls.Add(prompt)
		_tabs.TabPages.AddRange((activitiesPage, promptPage))

		self.Controls.Add(_tabs)

		_timer.Start()

	def UpdateNotifyText():
		if _current is null:
			_notify.Text = self.Text
		else:
			_current.Finished = date.Now
			_notify.Text = _current.ToString()

	override def OnClosing(args as CancelEventArgs):
		Minimize()
		args.Cancel = true
		super(args)

	def Minimize():
		self.WindowState = WindowState.Minimized

	def _contextMenu_Popup(sender as ContextMenu):

		sender.MenuItems.Clear()

		for project in _system.Projects:
			sender.MenuItems.Add(CreateProjectMenuItem(project))

		sender.MenuItems.Add(MenuItem("-"))
		sender.MenuItems.Add(
			MenuItem(Text: "New Project",
					Click: NewProject))
		sender.MenuItems.Add(MenuItem("-"))
		sender.MenuItems.Add(
			MenuItem(Text: "Quit",
					Click: Application.Exit))

	def CreateProjectMenuItem(project as Project):
		menu = MenuItem(Text: project.Name)
		for t in _system.QueryTasksByProject(project):
			menu.MenuItems.Add(
				MenuItem(Text: t.Name, Click: { StartTask(t) }))

		menu.MenuItems.Add(MenuItem("-"))
		menu.MenuItems.Add(
			MenuItem(Text: "New Task",
					Click: { NewTask(project) }))
		return menu

	def CreateContextMenu():
		return System.Windows.Forms.ContextMenu(Popup: _contextMenu_Popup)

	def FlushCurrentActivity():
		 return if _current is null

		 _current.Finished = date.Now
		 _system.AddActivity(_current)

		 _current = null

	def StartTask(task as Task):
		FlushCurrentActivity()
		_current = Activity(Task: task, Started: date.Now)
		UpdateNotifyText()

	def NewTask(project as Project):
		name = Prompt("New Task", "Task Name: ")
		if name is not null:
			_system.AddTask(Task(Project: project, Name: name))

	def NewProject():
		name = Prompt("New Project", "Project's Name: ")
		if name is not null:
			_system.AddProject(Project(Name: name))

	def Prompt(title as string, message as string):
		dlg = PromptDialog(Text: title,
						Message: message,
						Font: self.Font,
						StartPosition: FormStartPosition.CenterScreen)
		if DialogResult.OK == dlg.ShowDialog():
			return dlg.Value

	override def Dispose(disposing as bool):
		FlushCurrentActivity()
		_components.Dispose()
		_system.Dispose()
		super(disposing)

class PromptDialog(Form):

	_value as TextBox
	_message as Label

	def constructor():

		_message = Label(Location: Point(2, 2),
						Size: System.Drawing.Size(200, 18))
		_value = TextBox(
						Location: Point(2, 20),
						Size: System.Drawing.Size(290, 18))

		ok = Button(Text: "OK",
					Location: Point(50, 45),
					DialogResult: DialogResult.OK)

		cancel = Button(Text: "Cancel",
					Location: Point(150, 45),
					DialogResult: DialogResult.Cancel)

		SuspendLayout()
		self.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog
		self.StartPosition = FormStartPosition.CenterParent
		self.Size = System.Drawing.Size(300, 120)
		self.AcceptButton = ok
		self.CancelButton = cancel
		Controls.Add(_message)
		Controls.Add(_value)
		Controls.Add(ok)
		Controls.Add(cancel)
		ResumeLayout(false)

	Message as string:
		set:
			_message.Text = value

	Value:
		get:
			return _value.Text
		set:
			_value.Text = value

Application.Run(MainForm())

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

"""
This example shows how to use db4o 3.0 (http://www.db4o.com), a great
oodbm infrastructure, to implement a simple time tracking application.
"""

namespace TimeTracker

import System
import System.ComponentModel
import System.IO
import System.Drawing
import System.Windows.Forms
import TimeTracker.Model

class MainForm(Form):

	_system as TimeTrackerSystem

	_components = System.ComponentModel.Container()

	_current as Activity

	_tabs = TabControl(Dock: DockStyle.Fill)

	_view = ListView(View: View.Details, Dock: DockStyle.Fill)

	def constructor():
		self.Text = "Boo Time Tracker (powered by db4o)"
		self.ShowInTaskbar = false
		self.MinimizeBox = false
		Minimize()

		notify = NotifyIcon(_components,
				Text: self.Text,
				Icon: self.Icon,
				Visible: true,
				ContextMenu: CreateContextMenu(),
				DoubleClick: { self.WindowState = WindowState.Normal })

		_system = TimeTrackerSystem(
						Path.Combine(
							Application.UserAppDataPath,
							"timetracker.yap"))

		activitiesPage = TabPage(Text: "Activities")
		activitiesPage.Controls.Add(_view)

		prompt = booish.gui.PromptBox(
						Font: System.Drawing.Font("Lucida Console", 11))
		prompt.Interpreter.SetValue("system", _system)
		prompt.Interpreter.SetValue("MainForm", self)
		prompt.Interpreter.References.Add(typeof(Project).Assembly)
		promptPage = TabPage(Text: "Console")
		promptPage.Controls.Add(prompt)
		_tabs.TabPages.AddRange((activitiesPage, promptPage))

		self.Controls.Add(_tabs)

	override def OnClosing(args as CancelEventArgs):
		Minimize()
		args.Cancel = true
		super(args)

	def Minimize():
		self.WindowState = WindowState.Minimized

	def _contextMenu_Popup(sender as ContextMenu):

		sender.MenuItems.Clear()

		for project in _system.Projects:
			sender.MenuItems.Add(CreateProjectMenuItem(project))

		sender.MenuItems.Add(MenuItem("-"))
		sender.MenuItems.Add(
			MenuItem(Text: "New Project",
					Click: NewProject))
		sender.MenuItems.Add(MenuItem("-"))
		sender.MenuItems.Add(
			MenuItem(Text: "Quit",
					Click: Application.Exit))

	def CreateProjectMenuItem(project as Project):
		menu = MenuItem(Text: project.Name)
		for t in _system.QueryTasksByProject(project):
			menu.MenuItems.Add(
				MenuItem(Text: t.Name, Click: { StartTask(t) }))

		menu.MenuItems.Add(MenuItem("-"))
		menu.MenuItems.Add(
			MenuItem(Text: "New Task",
					Click: { NewTask(project) }))
		return menu

	def CreateContextMenu():
		return System.Windows.Forms.ContextMenu(Popup: _contextMenu_Popup)

	def FlushCurrentActivity():
		 return if _current is null

		 _current.Finished = date.Now
		 _system.AddActivity(_current)

		 _current = null

	def StartTask(task as Task):
		FlushCurrentActivity()
		_current = Activity(Task: task, Started: date.Now)

	def NewTask(project as Project):
		name = Prompt("New Task", "Task Name: ")
		if name is not null:
			_system.AddTask(Task(Project: project, Name: name))

	def NewProject():
		name = Prompt("New Project", "Project's Name: ")
		if name is not null:
			_system.AddProject(Project(Name: name))

	def Prompt(title as string, message as string):
		dlg = PromptDialog(Text: title,
						Message: message,
						Font: self.Font,
						StartPosition: FormStartPosition.CenterScreen)
		if DialogResult.OK == dlg.ShowDialog():
			return dlg.Value

	override def Dispose(disposing as bool):
		FlushCurrentActivity()
		_components.Dispose()
		_system.Dispose()
		super(disposing)

class PromptDialog(Form):

	_value as TextBox
	_message as Label

	def constructor():

		_message = Label(Location: Point(2, 2),
						Size: System.Drawing.Size(200, 18))
		_value = TextBox(
						Location: Point(2, 20),
						Size: System.Drawing.Size(290, 18))

		ok = Button(Text: "OK",
					Location: Point(50, 45),
					DialogResult: DialogResult.OK)

		cancel = Button(Text: "Cancel",
					Location: Point(150, 45),
					DialogResult: DialogResult.Cancel)

		SuspendLayout()
		self.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog
		self.StartPosition = FormStartPosition.CenterParent
		self.Size = System.Drawing.Size(300, 120)
		self.AcceptButton = ok
		self.CancelButton = cancel
		Controls.Add(_message)
		Controls.Add(_value)
		Controls.Add(ok)
		Controls.Add(cancel)
		ResumeLayout(false)

	Message as string:
		set:
			_message.Text = value

	Value:
		get:
			return _value.Text
		set:
			_value.Text = value

Application.Run(MainForm())


code cleanup

code cleanup

namespace UnityScript

import Boo.Lang.Compiler

class UnityScriptCompiler:

	[getter(Parameters)]
	_parameters = UnityScriptCompilerParameters()
	_compiler = BooCompiler(_parameters)

	def Run():
		return _compiler.Run()

	def Run(compileUnit as Boo.Lang.Compiler.Ast.CompileUnit):
		return _compiler.Run(compileUnit)

	static class Pipelines:

		def RawParsing():
			pipeline = CompilerPipeline()
			pipeline.Add(UnityScript.Steps.PreProcess())
			pipeline.Add(UnityScript.Steps.Parse())
			return pipeline

		def Parse():
			pipeline = RawParsing()
			pipeline.Add(UnityScript.Steps.ApplySemantics())
			return pipeline

		def Compile():
			return AdjustBooPipeline(Boo.Lang.Compiler.Pipelines.Compile())

		def CompileToMemory():
			return AdjustBooPipeline(Boo.Lang.Compiler.Pipelines.CompileToMemory())

		def CompileToFile():
			return AdjustBooPipeline(Boo.Lang.Compiler.Pipelines.CompileToFile())

		def CompileToBoo():
			return AdjustBooPipeline(Boo.Lang.Compiler.Pipelines.CompileToBoo())

		def AdjustBooPipeline(pipeline as CompilerPipeline):
			pipeline.Insert(0, UnityScript.Steps.PreProcess())

			pipeline.Replace(Boo.Lang.Parser.BooParsingStep, UnityScript.Steps.Parse())

			pipeline.Replace(Boo.Lang.Compiler.Steps.InitializeTypeSystemServices,
						UnityScript.Steps.InitializeUnityScriptTypeSystem())

			pipeline.Replace(Boo.Lang.Compiler.Steps.IntroduceGlobalNamespaces,
						UnityScript.Steps.IntroduceUnityGlobalNamespaces())

			pipeline.InsertAfter(Boo.Lang.Compiler.Steps.PreErrorChecking,
								UnityScript.Steps.ApplySemantics())

			pipeline.InsertBefore(Boo.Lang.Compiler.Steps.ExpandDuckTypedExpressions,
						UnityScript.Steps.ProcessAssignmentToDuckMembers())

			pipeline.Replace(Boo.Lang.Compiler.Steps.ProcessMethodBodiesWithDuckTyping,
						UnityScript.Steps.ProcessUnityScriptMethods())

			pipeline.InsertAfter(UnityScript.Steps.ProcessUnityScriptMethods,
						UnityScript.Steps.ProcessEvalInvocations())

			pipeline.ReplaceOptional(Boo.Lang.Compiler.Steps.ExpandDuckTypedExpressions,
						UnityScript.Steps.ExpandUnityDuckTypedExpressions())

			pipeline.ReplaceOptional(Boo.Lang.Compiler.Steps.ExpandVarArgsMethodInvocations,
						UnityScript.Steps.UnityExpandVarArgsMethodInvocations())

			pipeline.InsertBefore(Boo.Lang.Compiler.Steps.EmitAssembly,
						UnityScript.Steps.EnableRawArrayIndexing())

			pipeline.InsertAfter(Boo.Lang.Compiler.Steps.BindBaseTypes,
						UnityScript.Steps.CheckBaseTypes())

			return pipeline

[Extension]
def ReplaceOptional(pipeline as CompilerPipeline, optionalPipelineStepType as System.Type, step as ICompilerStep):
	index = pipeline.Find(optionalPipelineStepType)
	if index < 0: return
	pipeline.RemoveAt(index)
	pipeline.Insert(index-1, step)

namespace UnityScript

import Boo.Lang.Compiler

class UnityScriptCompiler:

	[getter(Parameters)]
	_parameters = UnityScriptCompilerParameters()
	_compiler = BooCompiler(_parameters)

	def Run():
		return _compiler.Run()

	def Run(compileUnit as Boo.Lang.Compiler.Ast.CompileUnit):
		return _compiler.Run(compileUnit)

	class Pipelines:

		static def RawParsing():
			pipeline = CompilerPipeline()
			pipeline.Add(UnityScript.Steps.PreProcess())
			pipeline.Add(UnityScript.Steps.Parse())
			return pipeline

		static def Parse():
			pipeline = RawParsing()
			pipeline.Add(UnityScript.Steps.ApplySemantics())
			return pipeline

		static def Compile():
			return AdjustBooPipeline(Boo.Lang.Compiler.Pipelines.Compile())

		static def CompileToMemory():
			return AdjustBooPipeline(Boo.Lang.Compiler.Pipelines.CompileToMemory())

		static def CompileToFile():
			return AdjustBooPipeline(Boo.Lang.Compiler.Pipelines.CompileToFile())

		static def CompileToBoo():
			return AdjustBooPipeline(Boo.Lang.Compiler.Pipelines.CompileToBoo())

		static def AdjustBooPipeline(pipeline as CompilerPipeline):
			pipeline.Insert(0, UnityScript.Steps.PreProcess())

			pipeline.Replace(Boo.Lang.Parser.BooParsingStep, UnityScript.Steps.Parse())

			pipeline.Replace(Boo.Lang.Compiler.Steps.InitializeTypeSystemServices,
						UnityScript.Steps.InitializeUnityScriptTypeSystem())

			pipeline.Replace(Boo.Lang.Compiler.Steps.IntroduceGlobalNamespaces,
						UnityScript.Steps.IntroduceUnityGlobalNamespaces())

			pipeline.InsertAfter(Boo.Lang.Compiler.Steps.PreErrorChecking,
								UnityScript.Steps.ApplySemantics())

			pipeline.InsertBefore(Boo.Lang.Compiler.Steps.ExpandDuckTypedExpressions,
						UnityScript.Steps.ProcessAssignmentToDuckMembers())

			pipeline.Replace(Boo.Lang.Compiler.Steps.ProcessMethodBodiesWithDuckTyping,
						UnityScript.Steps.ProcessUnityScriptMethods())

			pipeline.InsertAfter(UnityScript.Steps.ProcessUnityScriptMethods,
						UnityScript.Steps.ProcessEvalInvocations())

			pipeline.ReplaceOptional(Boo.Lang.Compiler.Steps.ExpandDuckTypedExpressions,
						UnityScript.Steps.ExpandUnityDuckTypedExpressions())

			pipeline.ReplaceOptional(Boo.Lang.Compiler.Steps.ExpandVarArgsMethodInvocations,
						UnityScript.Steps.UnityExpandVarArgsMethodInvocations())

			pipeline.InsertBefore(Boo.Lang.Compiler.Steps.EmitAssembly,
						UnityScript.Steps.EnableRawArrayIndexing())

			pipeline.InsertAfter(Boo.Lang.Compiler.Steps.BindBaseTypes,
						UnityScript.Steps.CheckBaseTypes())

			return pipeline

[Extension] def ReplaceOptional(pipeline as CompilerPipeline, optionalPipelineStepType as System.Type, step as ICompilerStep):
	index = pipeline.Find(optionalPipelineStepType)
	if index < 0: return
	pipeline.RemoveAt(index)
	pipeline.Insert(index-1, step)


better names

better names

namespace UnityScript.Steps

import UnityScript.Core

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

class ApplySemantics(AbstractVisitorCompilerStep):

	override def Run():
		Visit(CompileUnit)

	class DeclareGlobalVariables(DepthFirstTransformer):

		_class as ClassDefinition

		def constructor(cd as ClassDefinition):
			_class = cd

		override def EnterBlock(node as Block):
			if node.ParentNode isa Method: return true
			return false

		override def OnDeclarationStatement(node as DeclarationStatement):

			return if node.ContainsAnnotation('PrivateScope')

			field = [|
				public $(node.Declaration.Name) as $(node.Declaration.Type) = $(node.Initializer)
			|]
			field.LexicalInfo = node.LexicalInfo
			_class.Members.Add(field)

			RemoveCurrentNode()

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

	override def OnModule(module as Module):

		SetUpDefaultImports(module)

		script = FindOrCreateScriptClass(module)
		SetUpScriptClass(script)
		MoveMembers(module, script)
		SetUpMainMethod(module, script)
		MoveAttributes(module, script)
		module.Members.Add(script)
		SetScriptClass(Context, script)

	def SetUpMainMethod(module as Module, script as TypeDefinition):

		TransformGlobalVariablesIntoFields(module, script)

		main = ExistingMainMethodOn(script)
		if main is null:
			main = CreateMainMethod(module)
			script.Members.Add(main)
		else:
			Warnings.Add(UnityScriptWarnings.ScriptMainMethodIsImplicitlyDefined(main.LexicalInfo, main.Name))

		main.Body.Statements.Extend(module.Globals.Statements)
		module.Globals.Statements.Clear()

	def TransformGlobalVariablesIntoFields(module as Module, script as TypeDefinition):
		if not UnityScriptParameters.GlobalVariablesBecomeFields:
			return
		module.Globals.Accept(DeclareGlobalVariables(script))

	def ExistingMainMethodOn(typeDef as TypeDefinition):
		for member in typeDef.Members:
			method = member as Method
			isMainMethod = method is not null \
				and method.Name == ScriptMainMethod \
				and len(method.Parameters) == 0
			return method if isMainMethod

	def SetUpScriptClass(global as ClassDefinition):
		global.Modifiers |= TypeMemberModifiers.Partial
		SetMembersPublicByDefault(global)

	def SetUpDefaultImports(module as Module):
		for ns as string in self.UnityScriptParameters.Imports:
			module.Imports.Add(
				Import(LexicalInfo: module.LexicalInfo, Namespace: ns))

	def MoveAttributes(fromType as TypeDefinition, toType as TypeDefinition):
		toType.Attributes.Extend(fromType.Attributes)
		fromType.Attributes.Clear()

	def MoveMembers(fromType as TypeDefinition, toType as TypeDefinition):
		moved = []
		for member in fromType.Members:
			if not member isa TypeDefinition:
				movedMember = MovedMember(toType, member)
				toType.Members.Add(movedMember)
				Visit(movedMember)
				moved.Add(member)
			else:
				Visit(member)

		for member in moved:
			fromType.Members.Remove(member)

	def MovedMember(toType as TypeDefinition, member as TypeMember):
		if not toType.ContainsAnnotation("UserDefined"): return member
		if not IsConstructorMethod(toType, member): return member
		return ConstructorFromMethod(member)

	def IsConstructorMethod(toType as TypeDefinition, member as TypeMember):
		if member.NodeType != NodeType.Method: return false
		return toType.Name == member.Name

	def ConstructorFromMethod(method as Method):
		return Constructor(
			Parameters: method.Parameters,
			Body: method.Body,
			Attributes: method.Attributes,
			Modifiers: method.Modifiers,
			LexicalInfo: method.LexicalInfo,
			EndSourceLocation: method.EndSourceLocation)

	override def OnField(node as Field):
		SetPublicByDefault(node)

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

	override def OnMethod(node as Method):
		if node.IsPrivate: return

		SetPublicByDefault(node)
		if node.IsFinal: return
		if node.IsStatic: return
		node.Modifiers |= TypeMemberModifiers.Virtual

	def FindOrCreateScriptClass(module as Module):
		for existing as ClassDefinition in module.Members.Select(NodeType.ClassDefinition):
			if existing.Name == module.Name:
				module.Members.Remove(existing)
				if existing.IsPartial: AddScriptBaseType(existing)
				existing.Annotate("UserDefined")
				return existing

		klass = ClassDefinition(module.LexicalInfo, Name: module.Name, EndSourceLocation: module.EndSourceLocation)
		AddScriptBaseType(klass)
		return klass

	def AddScriptBaseType(klass as ClassDefinition):
		klass.BaseTypes.Add(CodeBuilder.CreateTypeReference(UnityScriptParameters.ScriptBaseType))

	def SetMembersPublicByDefault(node as ClassDefinition):
		for member in node.Members: Visit(member)

	def SetPublicByDefault(node as TypeMember):
		node.Modifiers |= TypeMemberModifiers.Public unless node.IsVisibilitySet

	ScriptMainMethod:
		get: return self.UnityScriptParameters.ScriptMainMethod

	def CreateMainMethod(module as Module):
		method = Method(module.LexicalInfo, Name: ScriptMainMethod)
		method.Modifiers = TypeMemberModifiers.Public | TypeMemberModifiers.Virtual

		stmts = module.Globals.Statements
		if len(stmts) > 0: method.LexicalInfo = Copy(stmts[0].LexicalInfo)
		method.EndSourceLocation = module.EndSourceLocation

		return method

def Copy(li as LexicalInfo):
	return LexicalInfo(li.FileName, li.Line, li.Column)

namespace UnityScript.Steps

import UnityScript.Core

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

class ApplySemantics(AbstractVisitorCompilerStep):

	override def Run():
		Visit(CompileUnit)

	class DeclareGlobalVariables(DepthFirstTransformer):

		_class as ClassDefinition

		def constructor(cd as ClassDefinition):
			_class = cd

		override def EnterBlock(node as Block):
			if node.ParentNode isa Method: return true
			return false

		override def OnDeclarationStatement(node as DeclarationStatement):

			return if node.ContainsAnnotation('PrivateScope')

			field = [|
				public $(node.Declaration.Name) as $(node.Declaration.Type) = $(node.Initializer)
			|]
			field.LexicalInfo = node.LexicalInfo
			_class.Members.Add(field)

			RemoveCurrentNode()

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

	override def OnModule(module as Module):

		SetUpDefaultImports(module)

		script = FindOrCreateScriptClass(module)
		SetUpScriptClass(script)
		MoveMembers(module, script)
		SetUpMainMethod(module, script)
		MoveAttributes(module, script)
		module.Members.Add(script)
		SetScriptClass(Context, script)

	def SetUpMainMethod(module as Module, script as TypeDefinition):

		TransformGlobalVariablesIntoFields(module, script)

		main = FindExistingMainMethodOn(script)
		if main is null:
			main = CreateMainMethod(module)
			script.Members.Add(main)
		else:
			Warnings.Add(UnityScriptWarnings.ScriptMainMethodIsImplicitlyDefined(main.LexicalInfo, main.Name))

		main.Body.Statements.Extend(module.Globals.Statements)
		module.Globals.Statements.Clear()

	def TransformGlobalVariablesIntoFields(module as Module, script as TypeDefinition):
		if not UnityScriptParameters.GlobalVariablesBecomeFields:
			return
		module.Globals.Accept(DeclareGlobalVariables(script))

	def FindExistingMainMethodOn(typeDef as TypeDefinition):
		for member in typeDef.Members:
			method = member as Method
			found = method is not null \
				and method.Name == ScriptMainMethod \
				and len(method.Parameters) == 0
			return method if found

	def SetUpScriptClass(global as ClassDefinition):
		global.Modifiers |= TypeMemberModifiers.Partial
		SetMembersPublicByDefault(global)

	def SetUpDefaultImports(module as Module):
		for ns as string in self.UnityScriptParameters.Imports:
			module.Imports.Add(
				Import(LexicalInfo: module.LexicalInfo, Namespace: ns))

	def MoveAttributes(fromType as TypeDefinition, toType as TypeDefinition):
		toType.Attributes.Extend(fromType.Attributes)
		fromType.Attributes.Clear()

	def MoveMembers(fromType as TypeDefinition, toType as TypeDefinition):
		moved = []
		for member in fromType.Members:
			if not member isa TypeDefinition:
				movedMember = MovedMember(toType, member)
				toType.Members.Add(movedMember)
				Visit(movedMember)
				moved.Add(member)
			else:
				Visit(member)

		for member in moved:
			fromType.Members.Remove(member)

	def MovedMember(toType as TypeDefinition, member as TypeMember):
		if not toType.ContainsAnnotation("UserDefined"): return member
		if not IsConstructorMethod(toType, member): return member
		return ConstructorFromMethod(member)

	def IsConstructorMethod(toType as TypeDefinition, member as TypeMember):
		if member.NodeType != NodeType.Method: return false
		return toType.Name == member.Name

	def ConstructorFromMethod(method as Method):
		return Constructor(
			Parameters: method.Parameters,
			Body: method.Body,
			Attributes: method.Attributes,
			Modifiers: method.Modifiers,
			LexicalInfo: method.LexicalInfo,
			EndSourceLocation: method.EndSourceLocation)

	override def OnField(node as Field):
		SetPublicByDefault(node)

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

	override def OnMethod(node as Method):
		if node.IsPrivate: return

		SetPublicByDefault(node)
		if node.IsFinal: return
		if node.IsStatic: return
		node.Modifiers |= TypeMemberModifiers.Virtual

	def FindOrCreateScriptClass(module as Module):
		for existing as ClassDefinition in module.Members.Select(NodeType.ClassDefinition):
			if existing.Name == module.Name:
				module.Members.Remove(existing)
				if existing.IsPartial: AddScriptBaseType(existing)
				existing.Annotate("UserDefined")
				return existing

		klass = ClassDefinition(module.LexicalInfo, Name: module.Name, EndSourceLocation: module.EndSourceLocation)
		AddScriptBaseType(klass)
		return klass

	def AddScriptBaseType(klass as ClassDefinition):
		klass.BaseTypes.Add(CodeBuilder.CreateTypeReference(UnityScriptParameters.ScriptBaseType))

	def SetMembersPublicByDefault(node as ClassDefinition):
		for member in node.Members: Visit(member)

	def SetPublicByDefault(node as TypeMember):
		node.Modifiers |= TypeMemberModifiers.Public unless node.IsVisibilitySet

	ScriptMainMethod:
		get: return self.UnityScriptParameters.ScriptMainMethod

	def CreateMainMethod(module as Module):
		method = Method(module.LexicalInfo, Name: ScriptMainMethod)
		method.Modifiers = TypeMemberModifiers.Public | TypeMemberModifiers.Virtual

		stmts = module.Globals.Statements
		if len(stmts) > 0: method.LexicalInfo = Copy(stmts[0].LexicalInfo)
		method.EndSourceLocation = module.EndSourceLocation

		return method

def Copy(li as LexicalInfo):
	return LexicalInfo(li.FileName, li.Line, li.Column)