Improve logical not folding

Improve logical not folding

namespace BooJs.Compiler.Steps

import Boo.Lang.Compiler
from Boo.Lang.Compiler.Ast import *
from Boo.Lang.Compiler.Steps import AbstractTransformerCompilerStep, IntroduceModuleClasses

from Boo.Lang.Environments import EnvironmentProvision
from Boo.Lang.Compiler.TypeSystem import EntityType
from Boo.Lang.Compiler.TypeSystem.Services import RuntimeMethodCache as BooRuntimeMethodCache
from Boo.Lang.Compiler.TypeSystem.Reflection import ExternalType
from BooJs.Compiler.TypeSystem import RuntimeMethodCache
from BooJs.Lang.Extensions import TransformAttribute, VarArgsAttribute

from System.Runtime.CompilerServices import CompilerGeneratedAttribute

class PrepareAst(AbstractTransformerCompilerStep):
"""
    Prepare the AST for its conversion to Javascript

        - Remove unneeded nodes
        - Convert builtins and runtime references

"""
    [getter(MethodCache)]
    private _methodCache as RuntimeMethodCache

    [getter(BooMethodCache)]
    private _booMethodCache as BooRuntimeMethodCache

    protected def HasAttribute[of T(System.Attribute)](node as Node):
        if ent = node.Entity as TypeSystem.IExternalEntity:
            return (HasAttribute[of T](ent) if ent else null as T)

        if anode = node as INodeWithAttributes:
            targetAttr = TypeSystemServices.Map(T)
            for attr in anode.Attributes:
                ctor = TypeSystemServices.GetEntity(attr) as TypeSystem.IConstructor
                if ctor and targetAttr == ctor.DeclaringType:
                    return true

        return false

    protected def HasAttribute[of T(System.Attribute)](entity as TypeSystem.IExternalEntity):
        return System.Attribute.GetCustomAttribute(entity.MemberInfo, typeof(T)) != null

    protected def IsCompilerGenerated(node as Node):
        return HasAttribute[of CompilerGeneratedAttribute](node)

    protected def IsBuiltin(node as Node) as bool:
        entity = node.Entity as TypeSystem.Reflection.ExternalType
        if not entity and centity = node.Entity as TypeSystem.ExternalMethod:
            entity = centity.DeclaringType

        return false if not entity
        return true if entity.Type is TypeSystemServices.BuiltinsType
        return entity.DeclaringType == TypeSystemServices.BuiltinsType

    protected def IsGlobal(node as Node) as bool:
        if entity = node.Entity as TypeSystem.Reflection.ExternalType:
            return entity.ActualType.Namespace == 'BooJs.Lang.Globals'

        return false

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

        _methodCache = EnvironmentProvision[of RuntimeMethodCache]()
        _booMethodCache = EnvironmentProvision[of BooRuntimeMethodCache]()

    def EnterModule(node as Module):
        if IsCompilerGenerated(node):
            RemoveCurrentNode()
            return false

        # TODO: Is this still needed?
        if node.Name == 'CompilerGenerated':
            RemoveCurrentNode()
            return false

        return true

    def EnterClassDefinition(node as ClassDefinition):
        if IsCompilerGenerated(node):
            RemoveCurrentNode()
            return false

        # TODO: Is this still needed?
        if node.Name == 'CompilerGeneratedExtensions':
            RemoveCurrentNode()
            return false

        return true

    def OnExpressionStatement(node as ExpressionStatement):
        # Ignore the assignment of locals produced by closures instrumentation
        be = node.Expression as BinaryExpression
        if be and be.Operator == BinaryOperatorType.Assign and be.Left.ToString() == '$locals':
            RemoveCurrentNode
            return

        # Ignore initialization value calls (__initobj__). We do it elsewhere.
        mie = node.Expression as MethodInvocationExpression
        if mie and mie.Target.Entity == TypeSystem.BuiltinFunction.InitValueType:
            RemoveCurrentNode
            return

        super(node)

    protected def ProcessReference(node as ReferenceExpression) as Node:
        if TransformAttribute.HasAttribute(node):
            result = TransformAttribute.Resolve(node, null)
            Visit result
            return result

        # Primitive type references
        if entity = node.Entity as ExternalType and TypeSystemServices.IsLiteralPrimitive(entity):
            return StringLiteralExpression(node.LexicalInfo, entity.FullName)

        # Check for builtins references
        if IsBuiltin(node):
            name = node.Name.Split(char('.'))[-1]
            refe = [| Boo.$(ReferenceExpression(Name: name)) |].withLexicalInfoFrom(node)
            refe.Entity = node.Entity
            return refe

        # Entities in the Global namespace are never prefixed
        if IsGlobal(node):
            node.Name = node.Name.Split(char('.'))[-1]
            return node

        # Members of the module are placed in the top scope
        intEntity = node.Entity as TypeSystem.IInternalEntity
        if intEntity and intEntity.EntityType in (EntityType.Type, EntityType.Constructor):
            # HACK: We should check for the Module attribute but I'm lazy right now :(
            if intEntity.Name.EndsWith('Module'):
                node.Name = 'exports'
                return node
            # Prefix type references in the same module with exports
            if intEntity.Node.LexicalInfo.FullPath == node.LexicalInfo.FullPath:
                mre = MemberReferenceExpression(
                    node.LexicalInfo,
                    Target: [| exports |],
                    Name: node.Name,
                    Entity: node.Entity,
                    ExpressionType: node.ExpressionType
                )
                return mre

        # Special handling for extension methods
        intMethod = node.Entity as TypeSystem.Internal.InternalMethod
        if intMethod and intMethod.IsExtension:
            if intMethod.Node.LexicalInfo.FullPath == node.LexicalInfo.FullPath:
                node.Name = 'exports.' + intMethod.Name
                return node

        return node

    def OnReferenceExpression(node as ReferenceExpression):
        ReplaceCurrentNode ProcessReference(node)

    def OnMemberReferenceExpression(node as MemberReferenceExpression):
        if TransformAttribute.HasAttribute(node):
            result = TransformAttribute.Resolve(node, null)
            Visit result
            ReplaceCurrentNode result
            return

        # Convert from `$locals.$variable` to `variable`
        if node.Target.NodeType == NodeType.ReferenceExpression:
            if (node.Target as ReferenceExpression).Name == '$locals':
                refexp = ReferenceExpression(node.Name[1:], LexicalInfo: node.LexicalInfo)
                ReplaceCurrentNode refexp
                return

        # Check for builtins references
        if IsBuiltin(node.Target):
            node.Target = [| Boo |].withLexicalInfoFrom(node.Target)

        super(node)

    def OnMethodInvocationExpression(node as MethodInvocationExpression):
        # Convert Transform attribute metadata to an AST annotation
        if TransformAttribute.HasAttribute(node.Target):
            result = TransformAttribute.Resolve(node.Target, node.Arguments)
            result = VisitNode(result)
            ReplaceCurrentNode result
            return

        if HasAttribute[of VarArgsAttribute](node.Target) and not node.ContainsAnnotation('varargs-processed'):
            node['varargs-processed'] = true
            // Common case where the only param is already an array
            if len(node.Arguments) == 1 and node.Arguments.Last isa ListLiteralExpression:
                last = node.Arguments.Last as ListLiteralExpression
                node.Arguments.Remove(last)
                for itm in last.Items:
                    node.Arguments.Add(itm)

                Visit(node.Arguments)
                return

            // Use .apply to call the method: ref.apply(target, [one, two].concat(params))
            params = ListLiteralExpression()
            for i in range(0, len(node.Arguments)-1):
                params.Items.Add( node.Arguments[i] )
            mie = [| $(params).concat($(node.Arguments.Last)) |]
            if node.Target isa MemberReferenceExpression:
                target = (node.Target as MemberReferenceExpression).Target
            else:
                target = [| Boo.UNDEF |]
            node = [| $(node.Target).apply($target, $mie) |]
            ReplaceCurrentNode node

        /*
        rts = TypeSystemServices.RuntimeType
        rtsInvoke = ResolveMethod(rts, 'Invoke')
        rtsInvokeCallable = ResolveMethod(rts, 'InvokeCallable')
        rtsInvokeBinaryOperator = ResolveMethod(rts, 'InvokeBinaryOperator')
        rtsInvokeUnaryOperator = ResolveMethod(rts, 'InvokeUnaryOperator')
        rtsSetProperty = ResolveMethod(rts, 'SetProperty')
        rtsGetProperty = ResolveMethod(rts, 'GetProperty')
        rtsSetSlice = ResolveMethod(rts, 'SetSlice')
        rtsGetSlice = ResolveMethod(rts, 'GetSlice')
        */

        if node.Target.Entity == MethodCache.InvokeBinaryOperator:

            # Convert it back into a binary expression
            be = BinaryExpression(node.LexicalInfo)
            be.ExpressionType = node.ExpressionType
            be.Left = node.Arguments[1]
            be.Right = node.Arguments[2]

            # Remove the op_ to find the operator type
            operator = (node.Arguments[0] as StringLiteralExpression).Value[3:]
            be.Operator = System.Enum.Parse(BinaryOperatorType, operator)

            ReplaceCurrentNode Visit(be)
            return

        if node.Target.Entity == MethodCache.InvokeUnaryOperator:
            # Convert it back into a unary expression
            ue = UnaryExpression(node.LexicalInfo)
            ue.ExpressionType = node.ExpressionType
            ue.Operand = node.Arguments[1]

            # Remove the op_ to find the operator type
            operator = (node.Arguments[0] as StringLiteralExpression).Value[3:]
            ue.Operator = System.Enum.Parse(UnaryOperatorType, operator)

            ReplaceCurrentNode Visit(ue)
            return

        super(node)

    protected def LocalsToDecls(locals as LocalCollection):
        # Convert locals back to simple declaration statements
        found = ['$locals']
        for local in locals:
            # Avoid duplicates
            if local.Name is null or local.Name in found:
                continue

            found.Push(local.Name)

            decl = Declaration(LexicalInfo: local.LexicalInfo)
            decl.Name = local.Name

            # Detect local type
            initializer as Expression = NullLiteralExpression()
            entity = local.Entity as TypeSystem.Internal.InternalLocal
            if entity:
                if entity.OriginalDeclaration:
                    # Skip declarations for those flagged as global
                    continue if entity.OriginalDeclaration.ContainsAnnotation('global')
                    decl.Type = entity.OriginalDeclaration.Type
                else:
                    # TODO: Can we generate proper type annotations with this?
                    decl.Type = SimpleTypeReference(Entity: entity)

                # Initialize with a default value
                if TypeSystemServices.IsNumber(entity.Type):
                    initializer = IntegerLiteralExpression(0)
                elif entity.Type == TypeSystemServices.TimeSpanType:
                    initializer = IntegerLiteralExpression(0)
                elif entity.Type == TypeSystemServices.BoolType:
                    initializer = BoolLiteralExpression(false)
                elif entity.Type == TypeSystemServices.StringType:
                    initializer = StringLiteralExpression('')

            yield DeclarationStatement(LexicalInfo: local.LexicalInfo, Declaration: decl, Initializer: initializer)

    def OnBlockExpression(node as BlockExpression):
    """ Convert locals annotation to declarations
    """
        if node.ContainsAnnotation('locals'):
            for st in LocalsToDecls(node['locals']):
                node.Body.Insert(0, st)
            node.RemoveAnnotation('locals')

        Visit node.Body

    def OnMethod(node as Method):
    """ Process locals and detect the Main method to move its statements into the Module globals
    """
        # Skip compiler generated methods
        if node.IsSynthetic and node.IsInternal:
            RemoveCurrentNode
            return

        for st in LocalsToDecls(node.Locals):
            node.Body.Insert(0, st)

        # Detect the Main method and move its statements to the Module globals
        if IsEntryPoint(node):
            Visit node.Body
            node.EnclosingModule.Globals = node.Body
            RemoveCurrentNode
            return

        super(node)

    def IsEntryPoint(node as Method):
        # Note: We cannot use ContextAnnotations.GetEntryPoint(Context) to detect
        # the entry point since when emitting the assembly we have to clone the AST
        # and then the node instance is different.
        return node.Name == IntroduceModuleClasses.EntryPointMethodName \
               and node.IsSynthetic and node.IsStatic and node.IsPrivate

    def OnCastExpression(node as CastExpression):
        mie = [| Boo.$(ReferenceExpression('cast'))() |]
        mie.LexicalInfo = node.LexicalInfo
        mie.Arguments.Add(node.Target)
        ReplaceCurrentNode( ProcessCast(mie, node.Type) )

    def OnTryCastExpression(node as TryCastExpression):
        mie = [| Boo.trycast() |]
        mie.LexicalInfo = node.LexicalInfo
        mie.Arguments.Add(node.Target)
        ReplaceCurrentNode( ProcessCast(mie, node.Type) )

    protected def ProcessCast(mie as MethodInvocationExpression, type as Node) as MethodInvocationExpression:
        if not type isa Expression:
            type = TypeofExpression(type.LexicalInfo, type)

        mie.Arguments.Add(type)
        return Visit(mie)

    def OnCharLiteralExpression(node as CharLiteralExpression):
    """ There is no char type in BooJs. char('c') and char(int) are converted to a string of length 1
    """
        ReplaceCurrentNode StringLiteralExpression(LexicalInfo: node.LexicalInfo, Value: node.Value)

    def OnRELiteralExpression(node as RELiteralExpression):
    """ Almost a direct translation to Javascript regexp literals. The only modification
        is that we ignore whitespace to allow the regexps to be somehow more readable while
        Boo's handling is to escape it as part of the match.

            / foo | bar /i  ->  /foo|bar/i
            @/ foo | bar /  ->  /foo|bar/i

        TODO: The ones prefixed with @ should be preprocessed to support new lines
    """
        re = node.Value
        start = re.IndexOf('/')
        stop = re.LastIndexOf('/')

        modifier = re[stop:]
        re = re[start:stop]

        # Ignore white space
        re = /\s+/.Replace(re, '')

        # Javascript does not support the single-line modifier (dot matches new lines).
        # We emulate it by converting dots to the [\s\S] expression in the regex.
        # NOTE: The algorithm will break when a dot is preceeded by an escaped back slash (\\.)
        if modifier.Contains('s'):
            re = /(?<!\\)\./.Replace(re, '[\\s\\S]')
            modifier = modifier.Replace('s', '')

        node.Value = re + modifier

    def OnArrayLiteralExpression(node as ArrayLiteralExpression):
    """ In BooJs arrays are muttable (Boo's Lists)
    """
        super(node)
        list = ListLiteralExpression(node.LexicalInfo, Items: node.Items)
        ReplaceCurrentNode list

    def OnUnlessStatement(node as UnlessStatement):
    """ Negate the condition to convert it into a simple if statement
    """
        ifst = IfStatement(LexicalInfo: node.LexicalInfo)
        ifst.Condition = UnaryExpression(
            Operator: UnaryOperatorType.LogicalNot,
            Operand: node.Condition,
            LexicalInfo: node.LexicalInfo
        )
        ifst.TrueBlock = node.Block

        ReplaceCurrentNode ifst

    def OnBinaryExpression(node as BinaryExpression):
        if node.Operator == BinaryOperatorType.TypeTest:
            mie = MethodInvocationExpression(node.LexicalInfo)
            mie.Target = ReferenceExpression(node.LexicalInfo, 'Boo.isa')
            mie.Arguments.Add(node.Left)
            mie.Arguments.Add(node.Right)
            Visit mie.Arguments
            ReplaceCurrentNode mie
            return

        super(node)

    def OnTypeofExpression(node as TypeofExpression):
        if st = node.Type as SimpleTypeReference:

            # Primitives are just enclosed as strings
            if TypeSystemServices.IsPrimitive(st.Name):
                ReplaceCurrentNode StringLiteralExpression(node.LexicalInfo, st.Name)
                return

            # If we have an entity use it
            if exent = st.Entity as TypeSystem.Reflection.ExternalType:
                refe = CodeBuilder.CreateReference(node.LexicalInfo, exent.ActualType)
                ReplaceCurrentNode ProcessReference(refe)
                return

            # Just rely on the type name
            refe = ReferenceExpression(node.LexicalInfo, st.Name)
            ReplaceCurrentNode ProcessReference(refe)

        elif node.Type isa ArrayTypeReference:

            refe = CodeBuilder.CreateReference(node.LexicalInfo, TypeSystemServices.ArrayType)
            ReplaceCurrentNode ProcessReference(refe)
            return

        else:
            raise 'Unsupported TypeReference: ' + node.Type + ' (' + node.Type.NodeType + ')'

    static _negated_binary_ops = {
        BinaryOperatorType.Equality: BinaryOperatorType.Inequality,
        BinaryOperatorType.Inequality: BinaryOperatorType.Equality,
        BinaryOperatorType.GreaterThan: BinaryOperatorType.LessThanOrEqual,
        BinaryOperatorType.GreaterThanOrEqual: BinaryOperatorType.LessThan,
        BinaryOperatorType.LessThan: BinaryOperatorType.GreaterThanOrEqual,
        BinaryOperatorType.LessThanOrEqual: BinaryOperatorType.GreaterThan,
    }

    def OnUnaryExpression(node as UnaryExpression):
    """ Fold logical not expressions to simplify the generated code. This is
        specially useful for normalizing `unless` conditions converted to `if not`
    """
        if node.Operator == UnaryOperatorType.LogicalNot:
            # not(not(expr)) -> expr
            if ue = node.Operand as UnaryExpression and ue.Operator == UnaryOperatorType.LogicalNot:
                ReplaceCurrentNode Visit(ue.Operand)
                return

            # not i != 10 -> i == 10
            if be = node.Operand as BinaryExpression:
                if be.Operator in _negated_binary_ops:
                    be.Operator = _negated_binary_ops[be.Operator]
                    ReplaceCurrentNode Visit(be)
                    return

        super(node)

    def OnBlock(node as Block):
    """ Flatten nested blocks. During the code transformation steps we may
        have introduced nested blocks as statements.
    """
        Visit node.Statements

        ofs = 0
        while ofs < len(node.Statements):
            st = node.Statements[ofs]
            if st.NodeType == NodeType.Block:
                node.Statements.Remove(st)
                for st2 in (st as Block).Statements:
                    node.Statements.Insert(ofs, st2)
                    ofs++
            else:
                ofs++

namespace BooJs.Compiler.Steps

import Boo.Lang.Compiler
from Boo.Lang.Compiler.Ast import *
from Boo.Lang.Compiler.Steps import AbstractTransformerCompilerStep, IntroduceModuleClasses

from Boo.Lang.Environments import EnvironmentProvision
from Boo.Lang.Compiler.TypeSystem import EntityType
from Boo.Lang.Compiler.TypeSystem.Services import RuntimeMethodCache as BooRuntimeMethodCache
from Boo.Lang.Compiler.TypeSystem.Reflection import ExternalType
from BooJs.Compiler.TypeSystem import RuntimeMethodCache
from BooJs.Lang.Extensions import TransformAttribute, VarArgsAttribute

from System.Runtime.CompilerServices import CompilerGeneratedAttribute

class PrepareAst(AbstractTransformerCompilerStep):
"""
    Prepare the AST for its conversion to Javascript

        - Remove unneeded nodes
        - Convert builtins and runtime references

"""
    [getter(MethodCache)]
    private _methodCache as RuntimeMethodCache

    [getter(BooMethodCache)]
    private _booMethodCache as BooRuntimeMethodCache

    protected def HasAttribute[of T(System.Attribute)](node as Node):
        if ent = node.Entity as TypeSystem.IExternalEntity:
            return (HasAttribute[of T](ent) if ent else null as T)

        if anode = node as INodeWithAttributes:
            targetAttr = TypeSystemServices.Map(T)
            for attr in anode.Attributes:
                ctor = TypeSystemServices.GetEntity(attr) as TypeSystem.IConstructor
                if ctor and targetAttr == ctor.DeclaringType:
                    return true

        return false

    protected def HasAttribute[of T(System.Attribute)](entity as TypeSystem.IExternalEntity):
        return System.Attribute.GetCustomAttribute(entity.MemberInfo, typeof(T)) != null

    protected def IsCompilerGenerated(node as Node):
        return HasAttribute[of CompilerGeneratedAttribute](node)

    protected def IsBuiltin(node as Node) as bool:
        entity = node.Entity as TypeSystem.Reflection.ExternalType
        if not entity and centity = node.Entity as TypeSystem.ExternalMethod:
            entity = centity.DeclaringType

        return false if not entity
        return true if entity.Type is TypeSystemServices.BuiltinsType
        return entity.DeclaringType == TypeSystemServices.BuiltinsType

    protected def IsGlobal(node as Node) as bool:
        if entity = node.Entity as TypeSystem.Reflection.ExternalType:
            return entity.ActualType.Namespace == 'BooJs.Lang.Globals'

        return false

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

        _methodCache = EnvironmentProvision[of RuntimeMethodCache]()
        _booMethodCache = EnvironmentProvision[of BooRuntimeMethodCache]()

    def EnterModule(node as Module):
        if IsCompilerGenerated(node):
            RemoveCurrentNode()
            return false

        # TODO: Is this still needed?
        if node.Name == 'CompilerGenerated':
            RemoveCurrentNode()
            return false

        return true

    def EnterClassDefinition(node as ClassDefinition):
        if IsCompilerGenerated(node):
            RemoveCurrentNode()
            return false

        # TODO: Is this still needed?
        if node.Name == 'CompilerGeneratedExtensions':
            RemoveCurrentNode()
            return false

        return true

    def OnExpressionStatement(node as ExpressionStatement):
        # Ignore the assignment of locals produced by closures instrumentation
        be = node.Expression as BinaryExpression
        if be and be.Operator == BinaryOperatorType.Assign and be.Left.ToString() == '$locals':
            RemoveCurrentNode
            return

        # Ignore initialization value calls (__initobj__). We do it elsewhere.
        mie = node.Expression as MethodInvocationExpression
        if mie and mie.Target.Entity == TypeSystem.BuiltinFunction.InitValueType:
            RemoveCurrentNode
            return

        super(node)

    protected def ProcessReference(node as ReferenceExpression) as Node:
        if TransformAttribute.HasAttribute(node):
            result = TransformAttribute.Resolve(node, null)
            Visit result
            return result

        # Primitive type references
        if entity = node.Entity as ExternalType and TypeSystemServices.IsLiteralPrimitive(entity):
            return StringLiteralExpression(node.LexicalInfo, entity.FullName)

        # Check for builtins references
        if IsBuiltin(node):
            name = node.Name.Split(char('.'))[-1]
            refe = [| Boo.$(ReferenceExpression(Name: name)) |].withLexicalInfoFrom(node)
            refe.Entity = node.Entity
            return refe

        # Entities in the Global namespace are never prefixed
        if IsGlobal(node):
            node.Name = node.Name.Split(char('.'))[-1]
            return node

        # Members of the module are placed in the top scope
        intEntity = node.Entity as TypeSystem.IInternalEntity
        if intEntity and intEntity.EntityType in (EntityType.Type, EntityType.Constructor):
            # HACK: We should check for the Module attribute but I'm lazy right now :(
            if intEntity.Name.EndsWith('Module'):
                node.Name = 'exports'
                return node
            # Prefix type references in the same module with exports
            if intEntity.Node.LexicalInfo.FullPath == node.LexicalInfo.FullPath:
                mre = MemberReferenceExpression(
                    node.LexicalInfo,
                    Target: [| exports |],
                    Name: node.Name,
                    Entity: node.Entity,
                    ExpressionType: node.ExpressionType
                )
                return mre

        # Special handling for extension methods
        intMethod = node.Entity as TypeSystem.Internal.InternalMethod
        if intMethod and intMethod.IsExtension:
            if intMethod.Node.LexicalInfo.FullPath == node.LexicalInfo.FullPath:
                node.Name = 'exports.' + intMethod.Name
                return node

        return node

    def OnReferenceExpression(node as ReferenceExpression):
        ReplaceCurrentNode ProcessReference(node)

    def OnMemberReferenceExpression(node as MemberReferenceExpression):
        if TransformAttribute.HasAttribute(node):
            result = TransformAttribute.Resolve(node, null)
            Visit result
            ReplaceCurrentNode result
            return

        # Convert from `$locals.$variable` to `variable`
        if node.Target.NodeType == NodeType.ReferenceExpression:
            if (node.Target as ReferenceExpression).Name == '$locals':
                refexp = ReferenceExpression(node.Name[1:], LexicalInfo: node.LexicalInfo)
                ReplaceCurrentNode refexp
                return

        # Check for builtins references
        if IsBuiltin(node.Target):
            node.Target = [| Boo |].withLexicalInfoFrom(node.Target)

        super(node)

    def OnMethodInvocationExpression(node as MethodInvocationExpression):
        # Convert Transform attribute metadata to an AST annotation
        if TransformAttribute.HasAttribute(node.Target):
            result = TransformAttribute.Resolve(node.Target, node.Arguments)
            result = VisitNode(result)
            ReplaceCurrentNode result
            return

        if HasAttribute[of VarArgsAttribute](node.Target) and not node.ContainsAnnotation('varargs-processed'):
            node['varargs-processed'] = true
            // Common case where the only param is already an array
            if len(node.Arguments) == 1 and node.Arguments.Last isa ListLiteralExpression:
                last = node.Arguments.Last as ListLiteralExpression
                node.Arguments.Remove(last)
                for itm in last.Items:
                    node.Arguments.Add(itm)

                Visit(node.Arguments)
                return

            // Use .apply to call the method: ref.apply(target, [one, two].concat(params))
            params = ListLiteralExpression()
            for i in range(0, len(node.Arguments)-1):
                params.Items.Add( node.Arguments[i] )
            mie = [| $(params).concat($(node.Arguments.Last)) |]
            if node.Target isa MemberReferenceExpression:
                target = (node.Target as MemberReferenceExpression).Target
            else:
                target = [| Boo.UNDEF |]
            node = [| $(node.Target).apply($target, $mie) |]
            ReplaceCurrentNode node

        /*
        rts = TypeSystemServices.RuntimeType
        rtsInvoke = ResolveMethod(rts, 'Invoke')
        rtsInvokeCallable = ResolveMethod(rts, 'InvokeCallable')
        rtsInvokeBinaryOperator = ResolveMethod(rts, 'InvokeBinaryOperator')
        rtsInvokeUnaryOperator = ResolveMethod(rts, 'InvokeUnaryOperator')
        rtsSetProperty = ResolveMethod(rts, 'SetProperty')
        rtsGetProperty = ResolveMethod(rts, 'GetProperty')
        rtsSetSlice = ResolveMethod(rts, 'SetSlice')
        rtsGetSlice = ResolveMethod(rts, 'GetSlice')
        */

        if node.Target.Entity == MethodCache.InvokeBinaryOperator:

            # Convert it back into a binary expression
            be = BinaryExpression(node.LexicalInfo)
            be.ExpressionType = node.ExpressionType
            be.Left = node.Arguments[1]
            be.Right = node.Arguments[2]

            # Remove the op_ to find the operator type
            operator = (node.Arguments[0] as StringLiteralExpression).Value[3:]
            be.Operator = System.Enum.Parse(BinaryOperatorType, operator)

            ReplaceCurrentNode Visit(be)
            return

        if node.Target.Entity == MethodCache.InvokeUnaryOperator:
            # Convert it back into a unary expression
            ue = UnaryExpression(node.LexicalInfo)
            ue.ExpressionType = node.ExpressionType
            ue.Operand = node.Arguments[1]

            # Remove the op_ to find the operator type
            operator = (node.Arguments[0] as StringLiteralExpression).Value[3:]
            ue.Operator = System.Enum.Parse(UnaryOperatorType, operator)

            ReplaceCurrentNode Visit(ue)
            return

        super(node)

    protected def LocalsToDecls(locals as LocalCollection):
        # Convert locals back to simple declaration statements
        found = ['$locals']
        for local in locals:
            # Avoid duplicates
            if local.Name is null or local.Name in found:
                continue

            found.Push(local.Name)

            decl = Declaration(LexicalInfo: local.LexicalInfo)
            decl.Name = local.Name

            # Detect local type
            initializer as Expression = NullLiteralExpression()
            entity = local.Entity as TypeSystem.Internal.InternalLocal
            if entity:
                if entity.OriginalDeclaration:
                    # Skip declarations for those flagged as global
                    continue if entity.OriginalDeclaration.ContainsAnnotation('global')
                    decl.Type = entity.OriginalDeclaration.Type
                else:
                    # TODO: Can we generate proper type annotations with this?
                    decl.Type = SimpleTypeReference(Entity: entity)

                # Initialize with a default value
                if TypeSystemServices.IsNumber(entity.Type):
                    initializer = IntegerLiteralExpression(0)
                elif entity.Type == TypeSystemServices.TimeSpanType:
                    initializer = IntegerLiteralExpression(0)
                elif entity.Type == TypeSystemServices.BoolType:
                    initializer = BoolLiteralExpression(false)
                elif entity.Type == TypeSystemServices.StringType:
                    initializer = StringLiteralExpression('')

            yield DeclarationStatement(LexicalInfo: local.LexicalInfo, Declaration: decl, Initializer: initializer)

    def OnBlockExpression(node as BlockExpression):
    """ Convert locals annotation to declarations
    """
        if node.ContainsAnnotation('locals'):
            for st in LocalsToDecls(node['locals']):
                node.Body.Insert(0, st)
            node.RemoveAnnotation('locals')

        Visit node.Body

    def OnMethod(node as Method):
    """ Process locals and detect the Main method to move its statements into the Module globals
    """
        # Skip compiler generated methods
        if node.IsSynthetic and node.IsInternal:
            RemoveCurrentNode
            return

        for st in LocalsToDecls(node.Locals):
            node.Body.Insert(0, st)

        # Detect the Main method and move its statements to the Module globals
        if IsEntryPoint(node):
            Visit node.Body
            node.EnclosingModule.Globals = node.Body
            RemoveCurrentNode
            return

        super(node)

    def IsEntryPoint(node as Method):
        # Note: We cannot use ContextAnnotations.GetEntryPoint(Context) to detect
        # the entry point since when emitting the assembly we have to clone the AST
        # and then the node instance is different.
        return node.Name == IntroduceModuleClasses.EntryPointMethodName \
               and node.IsSynthetic and node.IsStatic and node.IsPrivate

    def OnCastExpression(node as CastExpression):
        mie = [| Boo.$(ReferenceExpression('cast'))() |]
        mie.LexicalInfo = node.LexicalInfo
        mie.Arguments.Add(node.Target)
        ReplaceCurrentNode( ProcessCast(mie, node.Type) )

    def OnTryCastExpression(node as TryCastExpression):
        mie = [| Boo.trycast() |]
        mie.LexicalInfo = node.LexicalInfo
        mie.Arguments.Add(node.Target)
        ReplaceCurrentNode( ProcessCast(mie, node.Type) )

    protected def ProcessCast(mie as MethodInvocationExpression, type as Node) as MethodInvocationExpression:
        if not type isa Expression:
            type = TypeofExpression(type.LexicalInfo, type)

        mie.Arguments.Add(type)
        return Visit(mie)

    def OnCharLiteralExpression(node as CharLiteralExpression):
    """ There is no char type in BooJs. char('c') and char(int) are converted to a string of length 1
    """
        ReplaceCurrentNode StringLiteralExpression(LexicalInfo: node.LexicalInfo, Value: node.Value)

    def OnRELiteralExpression(node as RELiteralExpression):
    """ Almost a direct translation to Javascript regexp literals. The only modification
        is that we ignore whitespace to allow the regexps to be somehow more readable while
        Boo's handling is to escape it as part of the match.

            / foo | bar /i  ->  /foo|bar/i
            @/ foo | bar /  ->  /foo|bar/i

        TODO: The ones prefixed with @ should be preprocessed to support new lines
    """
        re = node.Value
        start = re.IndexOf('/')
        stop = re.LastIndexOf('/')

        modifier = re[stop:]
        re = re[start:stop]

        # Ignore white space
        re = /\s+/.Replace(re, '')

        # Javascript does not support the single-line modifier (dot matches new lines).
        # We emulate it by converting dots to the [\s\S] expression in the regex.
        # NOTE: The algorithm will break when a dot is preceeded by an escaped back slash (\\.)
        if modifier.Contains('s'):
            re = /(?<!\\)\./.Replace(re, '[\\s\\S]')
            modifier = modifier.Replace('s', '')

        node.Value = re + modifier

    def OnArrayLiteralExpression(node as ArrayLiteralExpression):
    """ In BooJs arrays are muttable (Boo's Lists)
    """
        super(node)
        list = ListLiteralExpression(node.LexicalInfo, Items: node.Items)
        ReplaceCurrentNode list

    def OnUnlessStatement(node as UnlessStatement):
    """ Negate the condition to convert it into a simple if statement
    """
        ifst = IfStatement(LexicalInfo: node.LexicalInfo)
        ifst.Condition = UnaryExpression(
            Operator: UnaryOperatorType.LogicalNot,
            Operand: node.Condition,
            LexicalInfo: node.LexicalInfo
        )
        ifst.TrueBlock = node.Block

        ReplaceCurrentNode ifst

    def OnBinaryExpression(node as BinaryExpression):
        if node.Operator == BinaryOperatorType.TypeTest:
            mie = MethodInvocationExpression(node.LexicalInfo)
            mie.Target = ReferenceExpression(node.LexicalInfo, 'Boo.isa')
            mie.Arguments.Add(node.Left)
            mie.Arguments.Add(node.Right)
            Visit mie.Arguments
            ReplaceCurrentNode mie
            return

        super(node)

    def OnTypeofExpression(node as TypeofExpression):
        if st = node.Type as SimpleTypeReference:

            # Primitives are just enclosed as strings
            if TypeSystemServices.IsPrimitive(st.Name):
                ReplaceCurrentNode StringLiteralExpression(node.LexicalInfo, st.Name)
                return

            # If we have an entity use it
            if exent = st.Entity as TypeSystem.Reflection.ExternalType:
                refe = CodeBuilder.CreateReference(node.LexicalInfo, exent.ActualType)
                ReplaceCurrentNode ProcessReference(refe)
                return

            # Just rely on the type name
            refe = ReferenceExpression(node.LexicalInfo, st.Name)
            ReplaceCurrentNode ProcessReference(refe)

        elif node.Type isa ArrayTypeReference:

            refe = CodeBuilder.CreateReference(node.LexicalInfo, TypeSystemServices.ArrayType)
            ReplaceCurrentNode ProcessReference(refe)
            return

        else:
            raise 'Unsupported TypeReference: ' + node.Type + ' (' + node.Type.NodeType + ')'

    def OnUnaryExpression(node as UnaryExpression):
        # Logical Not folding
        if node.Operator == UnaryOperatorType.LogicalNot:
            # not(not(expr)) -> expr
            if ue = node.Operand as UnaryExpression and ue.Operator == UnaryOperatorType.LogicalNot:
                ReplaceCurrentNode Visit(ue.Operand)
                return

            if be = node.Operand as BinaryExpression:
                inverses = {
                    BinaryOperatorType.Equality: BinaryOperatorType.Inequality,
                    BinaryOperatorType.Inequality: BinaryOperatorType.Equality,
                    BinaryOperatorType.GreaterThan: BinaryOperatorType.LessThanOrEqual,
                    BinaryOperatorType.LessThanOrEqual: BinaryOperatorType.GreaterThan,
                    BinaryOperatorType.LessThan: BinaryOperatorType.GreaterThanOrEqual,
                    BinaryOperatorType.GreaterThanOrEqual: BinaryOperatorType.LessThan,
                }

                if be.Operator in inverses:
                    be.Operator = inverses[be.Operator]
                    ReplaceCurrentNode Visit(be)
                    return

        super(node)

    def OnBlock(node as Block):

        Visit node.Statements

        # Flatten nested blocks
        ofs = 0
        while ofs < len(node.Statements):
            st = node.Statements[ofs]
            if st.NodeType == NodeType.Block:
                node.Statements.Remove(st)
                for st2 in (st as Block).Statements:
                    node.Statements.Insert(ofs, st2)
                    ofs++
            else:
                ofs++


Fixed expansion of varargs in closures

Fixed expansion of varargs in closures

namespace BooJs.Compiler.Steps

import Boo.Lang.Compiler.Steps(AbstractFastVisitorCompilerStep)
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem

class ExpandVarArgsMethodInvocations(AbstractFastVisitorCompilerStep):
"""
    This is a direct port of Boo's one. Using the original though there is a bug with
    invocations inside block expressions being converted to arrays twice.
"""
    public def Run():
        if len(Errors) > 0:
            return
        Visit(CompileUnit)

    override def OnMethodInvocationExpression(node as MethodInvocationExpression):
        # Make sure we only process invocations once
        return if node.ContainsAnnotation(self.GetType())
        node.Annotate(self.GetType())

        # Process first any invocations passed in as arguments
        Visit node.Arguments

        method = node.Target.Entity as IMethod;
        if (null != method and method.AcceptVarArgs):
            ExpandInvocation(node, method.GetParameters())
            return

        call = node.Target.ExpressionType as ICallableType
        if call != null:
            signature = call.GetSignature()
            if not signature.AcceptVarArgs: return

            ExpandInvocation(node, signature.Parameters)
            return

    protected virtual def ExpandInvocation(node as MethodInvocationExpression, parameters as (IParameter)):
        if AstUtil.InvocationEndsWithExplodeExpression(node):
            node.Arguments.ReplaceAt(-1, (node.Arguments[-1] as UnaryExpression).Operand)
            return

        lastParameterIndex = len(parameters)-1
        varArgType = parameters[lastParameterIndex].Type

        varArgs = node.Arguments.PopRange(lastParameterIndex)
        node.Arguments.Add(CodeBuilder.CreateArray(varArgType, varArgs))

namespace BooJs.Compiler.Steps

import Boo.Lang.Compiler.Steps(AbstractFastVisitorCompilerStep)
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem

class ExpandVarArgsMethodInvocations(AbstractFastVisitorCompilerStep):
"""
    This is a direct port of Boo's one. Using the original though there is a bug with
    invocations inside block expressions being converted to arrays twice.
"""
    public def Run():
        if len(Errors) > 0:
            return
        Visit(CompileUnit)

    override def OnMethodInvocationExpression(node as MethodInvocationExpression):
        # Process first any invocations passed in as arguments
        Visit node.Arguments

        method = node.Target.Entity as IMethod;
        if (null != method and method.AcceptVarArgs):
            ExpandInvocation(node, method.GetParameters())
            return

        call = node.Target.ExpressionType as ICallableType
        if call != null:
            signature = call.GetSignature()
            if not signature.AcceptVarArgs: return

            ExpandInvocation(node, signature.Parameters)
            return

    protected virtual def ExpandInvocation(node as MethodInvocationExpression, parameters as (IParameter)):
        if AstUtil.InvocationEndsWithExplodeExpression(node):
            node.Arguments.ReplaceAt(-1, (node.Arguments[-1] as UnaryExpression).Operand)
            return

        lastParameterIndex = len(parameters)-1
        varArgType = parameters[lastParameterIndex].Type

        varArgs = node.Arguments.PopRange(lastParameterIndex)
        node.Arguments.Add(CodeBuilder.CreateArray(varArgType, varArgs))


don't let syntax errors crash the application

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

import System
import System.IO
import Boo.IO
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Ast
import Gdk from "gdk-sharp" as Gdk
import Gtk from "gtk-sharp"
import GtkSourceView from "gtksourceview-sharp"
import BooExplorer.Common from BooExplorer.Common

class BooEditor(ScrolledWindow):

	static _booSourceLanguage = SourceLanguagesManager().GetLanguageFromMimeType("text/x-boo")

	[getter(Buffer)]
	_buffer = SourceBuffer(_booSourceLanguage,
							Highlight: true)

	_view = SourceView(_buffer,
						ShowLineNumbers: true,
						AutoIndent: true,
						TabsWidth: 4)

	[getter(FileName)]
	_fname as string

	Label:
		get:
			return System.IO.Path.GetFileName(_fname) if _fname
			return "unnamed.boo"

	def constructor():
		self.SetPolicy(PolicyType.Automatic, PolicyType.Automatic)
		self.Add(_view)

	def Open([required] fname as string):
		_buffer.Text = TextFile.ReadFile(fname)
		_buffer.Modified = false
		_fname = fname

	def SaveAs([required] fname as string):
		TextFile.WriteFile(fname, _buffer.Text)
		_fname = fname
		_buffer.Modified = false

	def Redo():
		_buffer.Redo()

	def Undo():
		_buffer.Undo()

class MainWindow(Window):

	_status = Statusbar(HasResizeGrip: false)
	_notebookEditors = Notebook(TabPos: PositionType.Top, Scrollable: true)
	_notebookHelpers = Notebook(TabPos: PositionType.Bottom, Scrollable: true)
	_notebookOutline = Notebook(TabPos: PositionType.Bottom, Scrollable: true)

	_documentOutline = TreeView()

	_output = TextView(Editable: false)
	_outputBuffer = _output.Buffer

	_accelGroup = AccelGroup()
	_editors = [] # workaround for gtk# bug #61703

	def constructor():
		super("Boo Explorer")

		self.AddAccelGroup(_accelGroup)
		self.Maximize()
		self.DeleteEvent += OnDelete

		_documentOutline.AppendColumn("Name", CellRendererText (), ("text", 0))
		_notebookOutline.AppendPage(CreateScrolled(_documentOutline), Label("Document Outline"))
		_notebookHelpers.AppendPage(CreateScrolled(_output), Label("Output"))

		vbox = VBox(false, 1)
		vbox.PackStart(CreateMenuBar(), false, false, 0)

		editPanel = VPaned()
		editPanel.Pack1(_notebookEditors, true, true)
		editPanel.Pack2(_notebookHelpers, false, true)

		mainPanel = HPaned()
		mainPanel.Pack2(_notebookOutline, false, false)
		mainPanel.Pack1(editPanel, true, true)

		vbox.PackStart(mainPanel, true, true, 0)
		vbox.PackStart(_status, false, false, 0)

		self.Add(vbox)

		self.NewDocument()

		Timeout.Add(3s.TotalMilliseconds, self.UpdateDocumentOutline)

	private def CreateScrolled(widget):
		sw = ScrolledWindow()
		sw.Add(widget)
		return sw

	private def AppendEditor(editor as BooEditor):
		_notebookEditors.AppendPage(editor, Label(editor.Label))
		_editors.Add(editor)
		editor.ShowAll()
		_notebookEditors.CurrentPage = _notebookEditors.NPages-1

	def NewDocument():
		self.AppendEditor(editor=BooEditor())
		return editor

	def OpenDocument(fname as string):
		editor = BooEditor()
		editor.Open(fname)
		self.AppendEditor(editor)
		return editor

	private def CreateMenuBar():
		mb = MenuBar()

		file = Menu()
		file.Append(ImageMenuItem(Stock.New, _accelGroup, Activated: _menuItemNew_Activated))
		file.Append(ImageMenuItem(Stock.Open, _accelGroup, Activated: _menuItemOpen_Activated))
		file.Append(ImageMenuItem(Stock.Save, _accelGroup, Activated: _menuItemSave_Activated))
		file.Append(SeparatorMenuItem())
		file.Append(ImageMenuItem(Stock.Quit, _accelGroup, Activated: _menuItemExit_Activated))

		edit = Menu()
		edit.Append(ImageMenuItem(Stock.Undo, _accelGroup, Activated: _menuItemUndo_Activated))
		edit.Append(ImageMenuItem(Stock.Redo, _accelGroup, Activated: _menuItemRedo_Activated))
		edit.Append(SeparatorMenuItem())
		edit.Append(ImageMenuItem(Stock.Cut, _accelGroup, Activated: _menuItemCut_Activated))
		edit.Append(ImageMenuItem(Stock.Copy, _accelGroup, Activated: _menuItemCopy_Activated))
		edit.Append(ImageMenuItem(Stock.Paste, _accelGroup, Activated: _menuItemPaste_Activated))
		edit.Append(ImageMenuItem(Stock.Delete, _accelGroup, Activated: _menuItemDelete_Activated))
		edit.Append(SeparatorMenuItem())
		edit.Append(ImageMenuItem(Stock.Preferences, _accelGroup))

		tools = Menu()
		tools.Append(mi=ImageMenuItem(Stock.Execute, _accelGroup, Activated: _menuItemExecute_Activated))
		mi.AddAccelerator("activate", _accelGroup, AccelKey(Gdk.Key.F5, Enum.ToObject(Gdk.ModifierType, 0), AccelFlags.Visible))
		tools.Append(miExpand=MenuItem("Expand", Activated: _menuItemExpand_Activated))
		miExpand.AddAccelerator("activate", _accelGroup, AccelKey(Gdk.Key.E, Gdk.ModifierType.ControlMask, AccelFlags.Visible))

		documents = Menu()
		documents.Append(ImageMenuItem(Stock.Close, _accelGroup, Activated: _menuItemClose_Activated))

		mb.Append(MenuItem("_File", Submenu: file))
		mb.Append(MenuItem("_Edit", Submenu: edit))
		mb.Append(MenuItem("_Tools", Submenu: tools))
		mb.Append(MenuItem("_Documents", Submenu: documents))
		return mb

	CurrentEditor as BooEditor:
		get:
			// can't do the simpler:
			// editor as BooEditor = _notebookEditors.CurrentPageWidget
			// because of gtk# bug #61703
			return _editors[_notebookEditors.CurrentPage]

	def AppendOutput(text as string):
		_outputBuffer.Insert(_outputBuffer.EndIter, text)

	def DisplayErrors(errors as CompilerErrorCollection):
		self.AppendOutput(errors.ToString(true)) if (len(errors))

	private def GetClipboard():
		return Clipboard.Get(Gdk.Selection.Clipboard)

	CurrentBuffer:
		get:
			return CurrentEditor.Buffer

	private def _menuItemClose_Activated(sender, args as EventArgs):
		_editors.RemoveAt(_notebookEditors.CurrentPage)
		_notebookEditors.RemovePage(_notebookEditors.CurrentPage)

	private def _menuItemCut_Activated(sender, args as EventArgs):
		CurrentBuffer.CutClipboard(GetClipboard(), true)

	private def _menuItemCopy_Activated(sender, args as EventArgs):
		CurrentBuffer.CopyClipboard(GetClipboard())

	private def _menuItemPaste_Activated(sender, args as EventArgs):
		CurrentBuffer.PasteClipboard(GetClipboard())

	private def _menuItemDelete_Activated(sender, args as EventArgs):
		pass

	private def _menuItemExecute_Activated(sender, args as EventArgs):

		_outputBuffer.Clear()
		self.AppendOutput("${_outputBuffer.Text}****** Compiling ${CurrentEditor.Label} *******\n")
		compiler = Boo.Lang.Compiler.BooCompiler()
		compiler.Parameters.Input.Add(StringInput(CurrentEditor.Label, 								CurrentEditor.Buffer.Text))
		compiler.Parameters.Pipeline = Boo.Lang.Compiler.Pipelines.Run()

		start = date.Now
		using console=ConsoleCapture():
			result = compiler.Run()
		self.DisplayErrors(result.Errors)
		self.AppendOutput(console.ToString())
		self.AppendOutput("Complete in ${date.Now-start}.")

	private def _menuItemNew_Activated(sender, args as EventArgs):
		self.NewDocument()

	private def _menuItemOpen_Activated(sender, args as EventArgs):
		fs = FileSelection("Open file", SelectMultiple: true)
		fs.Complete("*.boo")
		try:
			if cast(int, ResponseType.Ok) == fs.Run():
				for fname in fs.Selections:
					self.OpenDocument(fname)
		ensure:
			fs.Hide()

		self.UpdateDocumentOutline()

	private def UpdateDocumentOutline():
		try:
			DocumentOutlineProcessor(_documentOutline, CurrentEditor).Update()
		except ignored:
			pass
		return true // to match Gdk.Function signature

	private def _menuItemExpand_Activated(sender, args as EventArgs):
		editor = CurrentEditor

		compiler = BooCompiler()
		compiler.Parameters.OutputWriter = StringWriter()
		compiler.Parameters.Pipeline = Boo.Lang.Compiler.Pipelines.CompileToBoo()
		compiler.Parameters.Input.Add(StringInput(editor.Label, editor.Buffer.Text))
		result = compiler.Run()
		self.DisplayErrors(result.Errors)
		unless len(result.Errors):
			NewDocument().Buffer.Text = compiler.Parameters.OutputWriter.ToString()

	private def _menuItemSave_Activated(sender, args as EventArgs):
		editor = CurrentEditor

		fname = editor.FileName
		if fname is null:
			fs = FileSelection("Save As", SelectMultiple: false)
			if cast(int, ResponseType.Ok) != fs.Run():
				return
			fs.Hide()
			fname = fs.Selections[0]
		editor.SaveAs(fname)
		_notebookEditors.SetTabLabelText(editor, editor.Label)

	private def _menuItemUndo_Activated(sender, args as EventArgs):
		CurrentEditor.Undo()

	private def _menuItemRedo_Activated(sender, args as EventArgs):
		CurrentEditor.Redo()

	private def _menuItemExit_Activated(sender, args as EventArgs):
		Application.Quit()

	def OnDelete(sender, args as DeleteEventArgs):
		Application.Quit()
		args.RetVal = true

class DocumentOutlineProcessor:

	_store = TreeStore((string,))
	_documentOutline as TreeView
	_module as Boo.Lang.Compiler.Ast.Module

	def constructor(documentOutline, editor as BooEditor):
		_module = Parse(editor.Label, editor.Buffer.Text)
		_documentOutline = documentOutline

	def Parse(fname, text):
		compiler = BooCompiler()
		compiler.Parameters.Input.Add(StringInput(fname, text))
		compiler.Parameters.Pipeline = Pipelines.Parse()
		return compiler.Run().CompileUnit.Modules[0]

	def Update():
		for type in _module.Members:
			iter = _store.AppendValues((type.Name,))
			if type isa TypeDefinition:
				UpdateType(iter, type)
		_documentOutline.Model = _store
		_documentOutline.ExpandAll()

	def UpdateType(parent, type as TypeDefinition):
		for member in type.Members:
			iter = _store.AppendValues(parent, (member.Name,))

Application.Init()

MainWindow().ShowAll()

Application.Run()

import System
import System.IO
import Boo.IO
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Ast
import Gdk from "gdk-sharp" as Gdk
import Gtk from "gtk-sharp"
import GtkSourceView from "gtksourceview-sharp"
import BooExplorer.Common from BooExplorer.Common

class BooEditor(ScrolledWindow):

	static _booSourceLanguage = SourceLanguagesManager().GetLanguageFromMimeType("text/x-boo")

	[getter(Buffer)]
	_buffer = SourceBuffer(_booSourceLanguage,
							Highlight: true)

	_view = SourceView(_buffer,
						ShowLineNumbers: true,
						AutoIndent: true,
						TabsWidth: 4)

	[getter(FileName)]
	_fname as string

	Label:
		get:
			return System.IO.Path.GetFileName(_fname) if _fname
			return "unnamed.boo"

	def constructor():
		self.SetPolicy(PolicyType.Automatic, PolicyType.Automatic)
		self.Add(_view)

	def Open([required] fname as string):
		_buffer.Text = TextFile.ReadFile(fname)
		_buffer.Modified = false
		_fname = fname

	def SaveAs([required] fname as string):
		TextFile.WriteFile(fname, _buffer.Text)
		_fname = fname
		_buffer.Modified = false

	def Redo():
		_buffer.Redo()

	def Undo():
		_buffer.Undo()

class MainWindow(Window):

	_status = Statusbar(HasResizeGrip: false)
	_notebookEditors = Notebook(TabPos: PositionType.Top, Scrollable: true)
	_notebookHelpers = Notebook(TabPos: PositionType.Bottom, Scrollable: true)
	_notebookOutline = Notebook(TabPos: PositionType.Bottom, Scrollable: true)

	_documentOutline = TreeView()

	_output = TextView(Editable: false)
	_outputBuffer = _output.Buffer

	_accelGroup = AccelGroup()
	_editors = [] # workaround for gtk# bug #61703

	def constructor():
		super("Boo Explorer")

		self.AddAccelGroup(_accelGroup)
		self.Maximize()
		self.DeleteEvent += OnDelete

		_documentOutline.AppendColumn("Name", CellRendererText (), ("text", 0))
		_notebookOutline.AppendPage(CreateScrolled(_documentOutline), Label("Document Outline"))
		_notebookHelpers.AppendPage(CreateScrolled(_output), Label("Output"))

		vbox = VBox(false, 1)
		vbox.PackStart(CreateMenuBar(), false, false, 0)

		editPanel = VPaned()
		editPanel.Pack1(_notebookEditors, true, true)
		editPanel.Pack2(_notebookHelpers, false, true)

		mainPanel = HPaned()
		mainPanel.Pack2(_notebookOutline, false, false)
		mainPanel.Pack1(editPanel, true, true)

		vbox.PackStart(mainPanel, true, true, 0)
		vbox.PackStart(_status, false, false, 0)

		self.Add(vbox)

		self.NewDocument()

		Timeout.Add(3s.TotalMilliseconds, self.UpdateDocumentOutline)

	private def CreateScrolled(widget):
		sw = ScrolledWindow()
		sw.Add(widget)
		return sw

	private def AppendEditor(editor as BooEditor):
		_notebookEditors.AppendPage(editor, Label(editor.Label))
		_editors.Add(editor)
		editor.ShowAll()
		_notebookEditors.CurrentPage = _notebookEditors.NPages-1

	def NewDocument():
		self.AppendEditor(editor=BooEditor())
		return editor

	def OpenDocument(fname as string):
		editor = BooEditor()
		editor.Open(fname)
		self.AppendEditor(editor)
		return editor

	private def CreateMenuBar():
		mb = MenuBar()

		file = Menu()
		file.Append(ImageMenuItem(Stock.New, _accelGroup, Activated: _menuItemNew_Activated))
		file.Append(ImageMenuItem(Stock.Open, _accelGroup, Activated: _menuItemOpen_Activated))
		file.Append(ImageMenuItem(Stock.Save, _accelGroup, Activated: _menuItemSave_Activated))
		file.Append(SeparatorMenuItem())
		file.Append(ImageMenuItem(Stock.Quit, _accelGroup, Activated: _menuItemExit_Activated))

		edit = Menu()
		edit.Append(ImageMenuItem(Stock.Undo, _accelGroup, Activated: _menuItemUndo_Activated))
		edit.Append(ImageMenuItem(Stock.Redo, _accelGroup, Activated: _menuItemRedo_Activated))
		edit.Append(SeparatorMenuItem())
		edit.Append(ImageMenuItem(Stock.Cut, _accelGroup, Activated: _menuItemCut_Activated))
		edit.Append(ImageMenuItem(Stock.Copy, _accelGroup, Activated: _menuItemCopy_Activated))
		edit.Append(ImageMenuItem(Stock.Paste, _accelGroup, Activated: _menuItemPaste_Activated))
		edit.Append(ImageMenuItem(Stock.Delete, _accelGroup, Activated: _menuItemDelete_Activated))
		edit.Append(SeparatorMenuItem())
		edit.Append(ImageMenuItem(Stock.Preferences, _accelGroup))

		tools = Menu()
		tools.Append(mi=ImageMenuItem(Stock.Execute, _accelGroup, Activated: _menuItemExecute_Activated))
		mi.AddAccelerator("activate", _accelGroup, AccelKey(Gdk.Key.F5, Enum.ToObject(Gdk.ModifierType, 0), AccelFlags.Visible))
		tools.Append(miExpand=MenuItem("Expand", Activated: _menuItemExpand_Activated))
		miExpand.AddAccelerator("activate", _accelGroup, AccelKey(Gdk.Key.E, Gdk.ModifierType.ControlMask, AccelFlags.Visible))

		documents = Menu()
		documents.Append(ImageMenuItem(Stock.Close, _accelGroup, Activated: _menuItemClose_Activated))

		mb.Append(MenuItem("_File", Submenu: file))
		mb.Append(MenuItem("_Edit", Submenu: edit))
		mb.Append(MenuItem("_Tools", Submenu: tools))
		mb.Append(MenuItem("_Documents", Submenu: documents))
		return mb

	CurrentEditor as BooEditor:
		get:
			// can't do the simpler:
			// editor as BooEditor = _notebookEditors.CurrentPageWidget
			// because of gtk# bug #61703
			return _editors[_notebookEditors.CurrentPage]

	def AppendOutput(text as string):
		_outputBuffer.Insert(_outputBuffer.EndIter, text)

	def DisplayErrors(errors as CompilerErrorCollection):
		self.AppendOutput(errors.ToString(true)) if (len(errors))

	private def GetClipboard():
		return Clipboard.Get(Gdk.Selection.Clipboard)

	CurrentBuffer:
		get:
			return CurrentEditor.Buffer

	private def _menuItemClose_Activated(sender, args as EventArgs):
		_editors.RemoveAt(_notebookEditors.CurrentPage)
		_notebookEditors.RemovePage(_notebookEditors.CurrentPage)

	private def _menuItemCut_Activated(sender, args as EventArgs):
		CurrentBuffer.CutClipboard(GetClipboard(), true)

	private def _menuItemCopy_Activated(sender, args as EventArgs):
		CurrentBuffer.CopyClipboard(GetClipboard())

	private def _menuItemPaste_Activated(sender, args as EventArgs):
		CurrentBuffer.PasteClipboard(GetClipboard())

	private def _menuItemDelete_Activated(sender, args as EventArgs):
		pass

	private def _menuItemExecute_Activated(sender, args as EventArgs):

		_outputBuffer.Clear()
		self.AppendOutput("${_outputBuffer.Text}****** Compiling ${CurrentEditor.Label} *******\n")
		compiler = Boo.Lang.Compiler.BooCompiler()
		compiler.Parameters.Input.Add(StringInput(CurrentEditor.Label, 								CurrentEditor.Buffer.Text))
		compiler.Parameters.Pipeline = Boo.Lang.Compiler.Pipelines.Run()

		start = date.Now
		using console=ConsoleCapture():
			result = compiler.Run()
		self.DisplayErrors(result.Errors)
		self.AppendOutput(console.ToString())
		self.AppendOutput("Complete in ${date.Now-start}.")

	private def _menuItemNew_Activated(sender, args as EventArgs):
		self.NewDocument()

	private def _menuItemOpen_Activated(sender, args as EventArgs):
		fs = FileSelection("Open file", SelectMultiple: true)
		fs.Complete("*.boo")
		try:
			if cast(int, ResponseType.Ok) == fs.Run():
				for fname in fs.Selections:
					self.OpenDocument(fname)
		ensure:
			fs.Hide()

		self.UpdateDocumentOutline()

	private def UpdateDocumentOutline():
		DocumentOutlineProcessor(_documentOutline, CurrentEditor).Update()
		return true // to match Gdk.Function signature

	private def _menuItemExpand_Activated(sender, args as EventArgs):
		editor = CurrentEditor

		compiler = BooCompiler()
		compiler.Parameters.OutputWriter = StringWriter()
		compiler.Parameters.Pipeline = Boo.Lang.Compiler.Pipelines.CompileToBoo()
		compiler.Parameters.Input.Add(StringInput(editor.Label, editor.Buffer.Text))
		result = compiler.Run()
		self.DisplayErrors(result.Errors)
		unless len(result.Errors):
			NewDocument().Buffer.Text = compiler.Parameters.OutputWriter.ToString()

	private def _menuItemSave_Activated(sender, args as EventArgs):
		editor = CurrentEditor

		fname = editor.FileName
		if fname is null:
			fs = FileSelection("Save As", SelectMultiple: false)
			if cast(int, ResponseType.Ok) != fs.Run():
				return
			fs.Hide()
			fname = fs.Selections[0]
		editor.SaveAs(fname)
		_notebookEditors.SetTabLabelText(editor, editor.Label)

	private def _menuItemUndo_Activated(sender, args as EventArgs):
		CurrentEditor.Undo()

	private def _menuItemRedo_Activated(sender, args as EventArgs):
		CurrentEditor.Redo()

	private def _menuItemExit_Activated(sender, args as EventArgs):
		Application.Quit()

	def OnDelete(sender, args as DeleteEventArgs):
		Application.Quit()
		args.RetVal = true

class DocumentOutlineProcessor:

	_store = TreeStore((string,))
	_documentOutline as TreeView
	_module as Boo.Lang.Compiler.Ast.Module

	def constructor(documentOutline, editor as BooEditor):
		_module = Parse(editor.Label, editor.Buffer.Text)
		_documentOutline = documentOutline

	def Parse(fname, text):
		compiler = BooCompiler()
		compiler.Parameters.Input.Add(StringInput(fname, text))
		compiler.Parameters.Pipeline = Pipelines.Parse()
		return compiler.Run().CompileUnit.Modules[0]

	def Update():
		for type in _module.Members:
			iter = _store.AppendValues((type.Name,))
			if type isa TypeDefinition:
				UpdateType(iter, type)
		_documentOutline.Model = _store
		_documentOutline.ExpandAll()

	def UpdateType(parent, type as TypeDefinition):
		for member in type.Members:
			iter = _store.AppendValues(parent, (member.Name,))

Application.Init()

MainWindow().ShowAll()

Application.Run()


ApartmentState.STA before compiling or executing any code

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

#region license
// boo - an extensible programming language for the CLI
// Copyright (C) 2004 Rodrigo B. de Oliveira
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Contact Information
//
// mailto:rbo@acm.org
#endregion

import System
import System.IO
import System.Reflection
import System.Threading
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Pipeline
import Boo.Lang.Compiler.Pipeline.Definitions

class AssemblyResolver:

	_cache = {}

	def AddAssembly([required] asm as Assembly):
		_cache[GetSimpleName(asm.FullName)] = asm

	def AssemblyResolve(sender, args as ResolveEventArgs) as Assembly:
		simpleName = GetSimpleName(args.Name)

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

		return asm

	private def GetSimpleName(name as string):
		return /,\s*/.Split(name)[0]

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

def consume(reader as TextReader):
	writer = StringWriter()
	for line in reader:
		writer.WriteLine(line)
	return writer.ToString()

def main(argv as (string)):
	Thread.CurrentThread.ApartmentState = ApartmentState.STA

	compiler = BooCompiler()

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

	if "-" == argv[0]:
		compiler.Parameters.Input.Add(StringInput("<stdin>", consume(Console.In)))
	else:
		compiler.Parameters.Input.Add(FileInput(argv[0]))

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

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

#region license
// boo - an extensible programming language for the CLI
// Copyright (C) 2004 Rodrigo B. de Oliveira
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Contact Information
//
// mailto:rbo@acm.org
#endregion

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

class AssemblyResolver:

	_cache = {}

	def AddAssembly([required] asm as Assembly):
		_cache[GetSimpleName(asm.FullName)] = asm

	def AssemblyResolve(sender, args as ResolveEventArgs) as Assembly:
		simpleName = GetSimpleName(args.Name)

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

		return asm

	private def GetSimpleName(name as string):
		return /,\s*/.Split(name)[0]

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

def consume(reader as TextReader):
	writer = StringWriter()
	for line in reader:
		writer.WriteLine(line)
	return writer.ToString()

def main(argv as (string)):
	compiler = BooCompiler()

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

	if "-" == argv[0]:
		compiler.Parameters.Input.Add(StringInput("<stdin>", consume(Console.In)))
	else:
		compiler.Parameters.Input.Add(FileInput(argv[0]))

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

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


We can finally use a custom name provider

namespace BooJs.Compiler

import Boo.Lang.Compiler.Services.UniqueNameProvider as BooUniqueNameProvider

class UniqueNameProvider(BooUniqueNameProvider):
""" Generates unique names for the compilation unit
	TODO: Boo's class does not define the GetUniqueName method as virtual,
	      so it's not possible to inject our behaviour in the dependencies
	      environment.
"""
	_counters = {}

	override def GetUniqueName(*parts as (string)):
		prefix = join(parts, '_')
		if prefix not in _counters:
			_counters[prefix] = 0

		_counters[prefix] = (_counters[prefix] cast int) + 1
		return '_' + prefix + _counters[prefix] + '_'

	virtual def Reset():
		_counters = {}

namespace BooJs.Compiler

import Boo.Lang.Compiler.Services.UniqueNameProvider as BooUniqueNameProvider

class UniqueNameProvider(BooUniqueNameProvider):
""" Generates unique names for the compilation unit
	TODO: Boo's class does not define the GetUniqueName method as virtual,
	      so it's not possible to inject our behaviour in the dependencies
	      environment.
"""
	_counters = {}

	new def GetUniqueName(*parts as (string)):
		prefix = join(parts, '_')
		if prefix not in _counters:
			_counters[prefix] = 0

		_counters[prefix] = (_counters[prefix] cast int) + 1
		return '_' + prefix + _counters[prefix] + '_'

	virtual def Reset():
		_counters = {}


removed multi-file support for booi so you can pass parameters to your script.  Will have multi-file ability later with BOO-209.

git-svn-id: c3b8989232654601f1acea7403f771adaaa44a81@1457 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.IO
import System.Reflection
import System.Security.Permissions
import System.Threading
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Pipelines
import Boo.Lang.Compiler.Steps

class AssemblyResolver:

	_cache = {}

	def AddAssembly([required] asm as Assembly):
		_cache[GetSimpleName(asm.FullName)] = asm

	def AssemblyResolve(sender, args as ResolveEventArgs) as Assembly:
		simpleName = GetSimpleName(args.Name)

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

		return asm

	private def GetSimpleName(name as string):
		return /,\s*/.Split(name)[0]

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

def consume(reader as TextReader):
	return join(line for line in reader, "\n")

[STAThread]
def Main(argv as (string)):

	if len(argv) < 1:
		print("booi <script.boo>")
		return -1

	compiler = BooCompiler()

	compiler.Parameters.Pipeline = CompileToMemory()

	for arg in argv:
		if "-" == arg:
			compiler.Parameters.Input.Add(StringInput("<stdin>", consume(Console.In)))
			break
		elif "-ducky" == arg:
			compiler.Parameters.Ducky = true
		else:
			compiler.Parameters.Input.Add(FileInput(arg))
			break

	resolver = AssemblyResolver()
	AppDomain.CurrentDomain.AssemblyResolve += resolver.AssemblyResolve
	result = compiler.Run()
	if len(result.Errors):
		print(result.Errors.ToString(true))
		return -1
	else:
		try:
			resolver.AddAssembly(result.GeneratedAssembly)
			result.GeneratedAssemblyEntryPoint.Invoke(null, (argv[1:],))
		except x as TargetInvocationException:
			print(x.InnerException)
			return -1
	return 0

[assembly: SecurityPermission(
						SecurityAction.RequestMinimum,
						ControlAppDomain: true)]

#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 System.Reflection
import System.Security.Permissions
import System.Threading
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Pipelines
import Boo.Lang.Compiler.Steps

class AssemblyResolver:

	_cache = {}

	def AddAssembly([required] asm as Assembly):
		_cache[GetSimpleName(asm.FullName)] = asm

	def AssemblyResolve(sender, args as ResolveEventArgs) as Assembly:
		simpleName = GetSimpleName(args.Name)

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

		return asm

	private def GetSimpleName(name as string):
		return /,\s*/.Split(name)[0]

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

def consume(reader as TextReader):
	return join(line for line in reader, "\n")

[STAThread]
def Main(argv as (string)):

	if len(argv) < 1:
		print("booi <script.boo>")
		return -1

	compiler = BooCompiler()

	compiler.Parameters.Pipeline = CompileToMemory()

	for arg in argv:
		if "-" == arg:
			compiler.Parameters.Input.Add(StringInput("<stdin>", consume(Console.In)))
		elif "-ducky" == arg:
			compiler.Parameters.Ducky = true
		else:
			compiler.Parameters.Input.Add(FileInput(arg))

	resolver = AssemblyResolver()
	AppDomain.CurrentDomain.AssemblyResolve += resolver.AssemblyResolve
	result = compiler.Run()
	if len(result.Errors):
		print(result.Errors.ToString(true))
		return -1
	else:
		try:
			resolver.AddAssembly(result.GeneratedAssembly)
			result.GeneratedAssemblyEntryPoint.Invoke(null, (argv[1:],))
		except x as TargetInvocationException:
			print(x.InnerException)
			return -1
	return 0

[assembly: SecurityPermission(
						SecurityAction.RequestMinimum,
						ControlAppDomain: true)]


CastExpression

CastExpression

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

"""
it wasn't a string.
A STRING
"""
import System

def use(obj):
	try:
		print(cast(string, obj).ToUpper())
	except x as InvalidCastException:
		print("it wasn't a string.")

use(1)
use("a string")

"""
it wasn't a string
A STRING
"""
import System

def use(obj):
	try:
		print(cast(string, obj).ToUpper())
	except x as InvalidCastException:
		print("it wasn't a string.")

use(1)
use("a string")


-w command line option: print warnings

-w command line option: print warnings

git-svn-id: c3b8989232654601f1acea7403f771adaaa44a81@1714 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.IO
import System.Reflection
import System.Security.Permissions
import System.Threading
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Pipelines
import Boo.Lang.Compiler.Steps

class AssemblyResolver:

	_cache = {}

	def AddAssembly([required] asm as Assembly):
		_cache[GetSimpleName(asm.FullName)] = asm

	def AssemblyResolve(sender, args as ResolveEventArgs) as Assembly:
		simpleName = GetSimpleName(args.Name)

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

		return asm

	private def GetSimpleName(name as string):
		return /,\s*/.Split(name)[0]

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

def consume(reader as TextReader):
	return join(line for line in reader, "\n")

[STAThread]
def Main(argv as (string)):

	if len(argv) < 1:
		print("booi <script.boo>")
		return -1

	compiler = BooCompiler()
	compiler.Parameters.Pipeline = CompileToMemory()

	for arg in argv:
		if "-" == arg:
			compiler.Parameters.Input.Add(StringInput("<stdin>", consume(Console.In)))
			break
		elif "-ducky" == arg:
			compiler.Parameters.Ducky = true
		elif "-w" == arg:
			printWarnings = true
		else:
			compiler.Parameters.Input.Add(FileInput(arg))
			break

	resolver = AssemblyResolver()
	AppDomain.CurrentDomain.AssemblyResolve += resolver.AssemblyResolve
	result = compiler.Run()
	if printWarnings and len(result.Warnings):
		print(result.Warnings.ToString())
	if len(result.Errors):
		print(result.Errors.ToString(true))
		return -1
	else:
		try:
			resolver.AddAssembly(result.GeneratedAssembly)
			result.GeneratedAssembly.EntryPoint.Invoke(null, (argv[1:],))
		except x as TargetInvocationException:
			print(x.InnerException)
			return -1
	return 0

[assembly: SecurityPermission(
						SecurityAction.RequestMinimum,
						ControlAppDomain: true)]

#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 System.Reflection
import System.Security.Permissions
import System.Threading
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Pipelines
import Boo.Lang.Compiler.Steps

class AssemblyResolver:

	_cache = {}

	def AddAssembly([required] asm as Assembly):
		_cache[GetSimpleName(asm.FullName)] = asm

	def AssemblyResolve(sender, args as ResolveEventArgs) as Assembly:
		simpleName = GetSimpleName(args.Name)

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

		return asm

	private def GetSimpleName(name as string):
		return /,\s*/.Split(name)[0]

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

def consume(reader as TextReader):
	return join(line for line in reader, "\n")

[STAThread]
def Main(argv as (string)):

	if len(argv) < 1:
		print("booi <script.boo>")
		return -1

	compiler = BooCompiler()

	compiler.Parameters.Pipeline = CompileToMemory()

	for arg in argv:
		if "-" == arg:
			compiler.Parameters.Input.Add(StringInput("<stdin>", consume(Console.In)))
			break
		elif "-ducky" == arg:
			compiler.Parameters.Ducky = true
		else:
			compiler.Parameters.Input.Add(FileInput(arg))
			break

	resolver = AssemblyResolver()
	AppDomain.CurrentDomain.AssemblyResolve += resolver.AssemblyResolve
	result = compiler.Run()
	if len(result.Errors):
		print(result.Errors.ToString(true))
		return -1
	else:
		try:
			resolver.AddAssembly(result.GeneratedAssembly)
			result.GeneratedAssembly.EntryPoint.Invoke(null, (argv[1:],))
		except x as TargetInvocationException:
			print(x.InnerException)
			return -1
	return 0

[assembly: SecurityPermission(
						SecurityAction.RequestMinimum,
						ControlAppDomain: true)]


period not needed for codedom fileextension

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

// authors:
// Arron Washington
// Ian MacLean (original C# version)

namespace Boo.Lang.CodeDom

import System
import System.CodeDom.Compiler
class BooCodeProvider(CodeDomProvider):
"""Description of BooCodeProvider"""
	[getter(FileExtension)]
	_ext = "boo"

	def CreateCompiler():
		return BooCodeCompiler()
	def CreateGenerator():
		return BooCodeGenerator()
	override def GetConverter(type as Type) as System.ComponentModel.TypeConverter:
		raise NotImplementedException()

#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

// authors:
// Arron Washington
// Ian MacLean (original C# version)

namespace Boo.Lang.CodeDom

import System
import System.CodeDom.Compiler
class BooCodeProvider(CodeDomProvider):
"""Description of BooCodeProvider"""
	[getter(FileExtension)]
	_ext = ".boo"

	def CreateCompiler():
		return BooCodeCompiler()
	def CreateGenerator():
		return BooCodeGenerator()
	override def GetConverter(type as Type) as System.ComponentModel.TypeConverter:
		raise NotImplementedException()


fixed test case

fixed test case

#ignore work in progress
"""
First
Second
"""
import Boo.Lang.Environments

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

interface IFoo:
	def Bar() as string*

class ImplementIFoo(AbstractVisitorCompilerStep):

	override def Run():
		Visit(CompileUnit)

	override def LeaveClassDefinition(node as ClassDefinition):
		impl = [|
			class _($IFoo):

				callable OrdinalGenerator() as Ordinal*

				def Bar():
					generator as OrdinalGenerator = do:
						yield Ordinal.First
						yield Ordinal.Second
					for item in generator():
						yield item.ToString()

				enum Ordinal:
					First
					Second
		|]
		my(CodeReifier).MergeInto(node, impl)

module = [|
	import System

	class Foo:
		pass
|]

pipeline = Pipelines.CompileToMemory()
pipeline.InsertAfter(Steps.TypeInference, ImplementIFoo())

parameters = CompilerParameters(Pipeline: pipeline)
parameters.References.Add(typeof(IFoo).Assembly)

result = BooCompiler(parameters).Run(CompileUnit(module))
assert len(result.Errors) == 0, result.Errors.ToString(true)

foo as IFoo = result.GeneratedAssembly.GetType("Foo")()
for item in foo.Bar():
	print item

#ignore
"""
First
Second
"""
import Boo.Lang.Environments

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

interface IFoo:
	def Bar() as string*

class ImplementIFoo(AbstractVisitorCompilerStep):

	override def Run():
		Visit(CompileUnit)

	override def LeaveClassDefinition(node as ClassDefinition):
		impl = [|
			class _($IFoo):

				callable OrdinalGenerator() as Ordinal*

				def Bar():
					generator as OrdinalGenerator = do:
						yield Items.First
						yield Items.Second
					for item in generator():
						yield item.ToString()

				enum Ordinal:
					First
					Second
		|]
		my(CodeReifier).MergeInto(node, impl)

module = [|
	import System

	class Foo:
		pass
|]

pipeline = Pipelines.CompileToMemory()
pipeline.InsertAfter(Steps.TypeInference, ImplementIFoo())

parameters = CompilerParameters(Pipeline: pipeline)
parameters.References.Add(typeof(IFoo).Assembly)

result = BooCompiler(parameters).Run(CompileUnit(module))
assert len(result.Errors) == 0, result.Errors.ToString(true)

foo as IFoo = result.GeneratedAssembly.GetType("Foo")()
for item in foo.Bar():
	print item


'-' is no longer a valid class name character

namespace Boojay.Compilation.Tests

import System.IO

import NUnit.Framework from nunit.framework

import Boo.Lang.Parser
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Ast
import Boojay.Compilation

[TestFixture]
partial class IntegrationTest:

	def runTestCase(testFile as string):
		unit = parse(fullpathFor(testFile))
		main = unit.Modules[0]
		compile(unit)
		output = runJavaClass(moduleClassFor(main))
		Assert.IsNotNull(main.Documentation, "Expecting documentation for '${testFile}'")
		Assert.AreEqual(normalizeWhiteSpace(main.Documentation), normalizeWhiteSpace(output))

	def fullpathFor(testFile as string):
		eclipseBuildPath = Path.Combine("../boojay", testFile)
		return eclipseBuildPath if File.Exists(eclipseBuildPath)

		return Path.Combine("..", testFile)

	def normalizeWhiteSpace(s as string):
		return s.Trim().Replace("\r\n", "\n")

	def compile(unit as CompileUnit):
		compiler = newBoojayCompiler()
		result = compiler.Run(unit)
		assert 0 == len(result.Errors), result.Errors.ToString(true) + unit.ToCodeString()

	def parse(fname as string):
		return BooParser.ParseFile(System.IO.Path.GetFullPath(fname))

	def moduleClassFor(module as Module):
		return module.FullName.Replace("-", "_") + "Module"

	def runJavaClass(className as string):
		p = shellp("java", "-cp . ${className}")
		p.WaitForExit()
		if p.ExitCode != 0: raise p.StandardError.ReadToEnd()
		return p.StandardOutput.ReadToEnd()

namespace Boojay.Compilation.Tests

import System.IO

import NUnit.Framework from nunit.framework

import Boo.Lang.Parser
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Ast
import Boojay.Compilation

[TestFixture]
partial class IntegrationTest:

	def runTestCase(testFile as string):
		unit = parse(fullpathFor(testFile))
		main = unit.Modules[0]
		compile(unit)
		output = runJavaClass(moduleClassFor(main))
		Assert.IsNotNull(main.Documentation, "Expecting documentation for '${testFile}'")
		Assert.AreEqual(normalizeWhiteSpace(main.Documentation), normalizeWhiteSpace(output))

	def fullpathFor(testFile as string):
		eclipseBuildPath = Path.Combine("../boojay", testFile)
		return eclipseBuildPath if File.Exists(eclipseBuildPath)

		return Path.Combine("..", testFile)

	def normalizeWhiteSpace(s as string):
		return s.Trim().Replace("\r\n", "\n")

	def compile(unit as CompileUnit):
		compiler = newBoojayCompiler()
		result = compiler.Run(unit)
		assert 0 == len(result.Errors), result.Errors.ToString(true) + unit.ToCodeString()

	def parse(fname as string):
		return BooParser.ParseFile(System.IO.Path.GetFullPath(fname))

	def moduleClassFor(module as Module):
		return module.FullName + "Module"

	def runJavaClass(className as string):
		p = shellp("java", "-cp . ${className}")
		p.WaitForExit()
		if p.ExitCode != 0: raise p.StandardError.ReadToEnd()
		return p.StandardOutput.ReadToEnd()


bin update with latest fixes to booish

bin update with latest fixes to booish

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

class Functor(ICallable):
	def Call(args as (object)) as object:
		print("called with: " + join(args, ", "))

def each(items, function as callable):
	for item in items:
		function(item)

items = List(range(5))
each(items, Functor())
each(items, { item | print(item) })