removed debug prints

removed debug prints

namespace BooJs.Compiler.Steps

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

import Boo.Lang.Environments
import Boo.Lang.Compiler.TypeSystem.Services.RuntimeMethodCache as BooRuntimeMethodCache
import Boo.Lang.Compiler.TypeSystem.Reflection(ExternalType)
import BooJs.Compiler.TypeSystem(RuntimeMethodCache)
import BooJs.Lang.Extensions

import System.Runtime.CompilerServices(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 GetAttribute[of T(System.Attribute)](node as Node) as T:
        entity = node.Entity as TypeSystem.IExternalEntity
        return (GetAttribute[of T](entity) if entity else null as T)

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

    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 node.Name == 'CompilerGenerated':
            RemoveCurrentNode()
            return false

        return true

    def EnterClassDefinition(node as ClassDefinition):
        if node.Name == 'CompilerGeneratedExtensions':
            RemoveCurrentNode()
            return false

        if GetAttribute[of CompilerGeneratedAttribute](node):
            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
        ientity = node.Entity as TypeSystem.IMember
        if ientity and ientity.DeclaringType and ientity.DeclaringType.IsClass and ientity.DeclaringType.IsFinal:
            mre = MemberReferenceExpression(node.LexicalInfo)
            mre.Target = ReferenceExpression('exports', LexicalInfo: node.LexicalInfo)
            mre.Name = node.Name.Split(char('.'))[-1]
            return mre

        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

        # Members of the module are placed in the top scope
        ientity = node.Target.Entity as TypeSystem.Internal.AbstractInternalType
        if node.Target.IsSynthetic and ientity and ientity.IsClass and ientity.IsFinal:
            #refexp = ReferenceExpression(node.Name, LexicalInfo: node.LexicalInfo)
            #ReplaceCurrentNode refexp
            node.Target = ReferenceExpression('exports', LexicalInfo: node.LexicalInfo)
            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 GetAttribute[of VarArgsAttribute](node.Target) and not node.ContainsAnnotation('varargs-processed'):
            node['varargs-processed'] = true
            if node.Arguments[-1] isa ListLiteralExpression:
                last = node.Arguments[-1] as ListLiteralExpression
                node.Arguments.Remove(last)
                for itm in last.Items:
                    node.Arguments.Add(itm)
                return

            params = ListLiteralExpression()
            for i in range(0, len(node.Arguments)-1):
                params.Items.Add( node.Arguments[i] )
            mie = [| $(params).concat($(node.Arguments[-1])) |]
            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++

namespace BooJs.Compiler.Steps

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

import Boo.Lang.Environments
import Boo.Lang.Compiler.TypeSystem.Services.RuntimeMethodCache as BooRuntimeMethodCache
import Boo.Lang.Compiler.TypeSystem.Reflection(ExternalType)
import BooJs.Compiler.TypeSystem(RuntimeMethodCache)
import BooJs.Lang.Extensions

import System.Runtime.CompilerServices(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 GetAttribute[of T(System.Attribute)](node as Node) as T:
        entity = node.Entity as TypeSystem.IExternalEntity
        return (GetAttribute[of T](entity) if entity else null as T)

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

    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 node.Name == 'CompilerGenerated':
            RemoveCurrentNode()
            return false

        return true

    def EnterClassDefinition(node as ClassDefinition):
        if node.Name == 'CompilerGeneratedExtensions':
            RemoveCurrentNode()
            return false

        if GetAttribute[of CompilerGeneratedAttribute](node):
            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
        ientity = node.Entity as TypeSystem.IMember
        if ientity and ientity.DeclaringType and ientity.DeclaringType.IsClass and ientity.DeclaringType.IsFinal:
            mre = MemberReferenceExpression(node.LexicalInfo)
            mre.Target = ReferenceExpression('exports', LexicalInfo: node.LexicalInfo)
            mre.Name = node.Name.Split(char('.'))[-1]
            return mre

        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

        # Members of the module are placed in the top scope
        ientity = node.Target.Entity as TypeSystem.Internal.AbstractInternalType
        if node.Target.IsSynthetic and ientity and ientity.IsClass and ientity.IsFinal:
            #refexp = ReferenceExpression(node.Name, LexicalInfo: node.LexicalInfo)
            #ReplaceCurrentNode refexp
            node.Target = ReferenceExpression('exports', LexicalInfo: node.LexicalInfo)
            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 GetAttribute[of VarArgsAttribute](node.Target) and not node.ContainsAnnotation('varargs-processed'):
            node['varargs-processed'] = true
            if node.Arguments[-1] isa ListLiteralExpression:
                last = node.Arguments[-1] as ListLiteralExpression
                node.Arguments.Remove(last)
                for itm in last.Items:
                    node.Arguments.Add(itm)
                return

            params = ListLiteralExpression()
            for i in range(0, len(node.Arguments)-1):
                params.Items.Add( node.Arguments[i] )
            mie = [| $(params).concat($(node.Arguments[-1])) |]
            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
    """
        print 'M', node
        # Skip compiler generated methods
        if node.IsSynthetic and node.IsInternal:
            RemoveCurrentNode
            return
        print 'm', node

        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++


Changed internal-generic-type-3 testcase to not fail on peverify step for having an empty struct.
Boo should disallow empty value types, or figure out how to emit them properly if possible.

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

public struct GenericStruct of T:
	Field as T

assert typeof(GenericStruct of *).MakeGenericType(int) == typeof(GenericStruct of int)

public struct GenericStruct of T:
	pass

assert typeof(GenericStruct of *).MakeGenericType(int) == typeof(GenericStruct of int)


updated to compile with the latest code

updated to compile with the latest code

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

namespace StyleChecker

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

class StyleCheckerStep(AbstractVisitorCompilerStep):

	override def Run():
		Visit(CompileUnit)

	override def LeaveClassDefinition(node as ClassDefinition):
		if not System.Char.IsUpper(node.Name[0]):
			AddError(node, "Class name '${node.Name}' does not start with uppercase letter!")

	override def LeaveField(node as Field):
		if not node.IsPublic:
			if not node.Name.StartsWith("_"):
				AddError(node, "Field name '${node.Name}' does not start with '_'!")

	override def LeaveParameterDeclaration(node as ParameterDeclaration):
		if not System.Char.IsLower(node.Name[0]):
			AddError(node, "Parameter name '${node.Name}' does not start with lowercase letter!")

	def AddError(node as Node, message as string):
		Errors.Add(CompilerError(node, message))

class StyleCheckerPipeline(CompileToFile):

	def constructor():
		self.Insert(1, StyleCheckerStep())

#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

namespace StyleChecker

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

class StyleCheckerStep(AbstractVisitorCompilerStep):

	override def Run():
		Visit(CompileUnit)

	override def LeaveClassDefinition(node as ClassDefinition):
		if not System.Char.IsUpper(node.Name[0]):
			Error(node, "Class name '${node.Name}' does not start with uppercase letter!")

	override def LeaveField(node as Field):
		if not node.IsPublic:
			if not node.Name.StartsWith("_"):
				Error(node, "Field name '${node.Name}' does not start with '_'!")

	override def LeaveParameterDeclaration(node as ParameterDeclaration):
		if not System.Char.IsLower(node.Name[0]):
			Error(node, "Parameter name '${node.Name}' does not start with lowercase letter!")

	def Error(node as Node, message as string):
		Errors.Add(CompilerError(node, message))

class StyleCheckerPipeline(CompileToFile):

	def constructor():
		self.Insert(1, StyleCheckerStep())


Update publish target in build script

Update publish target in build script

include "build_support.boo"

solution = "MarkEmbling.Utils.sln"
configuration = "release"
test_assembly = "MarkEmbling.Utils.Tests/bin/${configuration}/MarkEmbling.Utils.Tests.dll"
bin_path = "build/bin"
package_path = "build/nuget"

target default, (compile, test, prep):
  pass

desc "Compiles the solution"
target compile:
  msbuild(file: solution, configuration: configuration, version: "4.0")

desc "Executes the tests"
target test, (compile):
  with nunit(assembly: test_assembly, toolPath: "packages/NUnit.Runners.2.6.2/tools/nunit-console.exe")

desc "Copies the binaries to the 'build/bin' directory"
target prep, (compile, test):
  rmdir(bin_path)

  with FileList("MarkEmbling.Utils/bin/${configuration}"):
    .Include("*.{dll,exe,config}")
    .ForEach def(file):
      file.CopyToDirectory(bin_path)

  with FileList("MarkEmbling.Utils.Forms/bin/${configuration}"):
    .Include("*.{dll,exe,config}")
    .ForEach def(file):
      file.CopyToDirectory(bin_path)

desc "Creates the NuGet packages"
target package, (prep):
  with FileList(package_path):
    .Include("*.nupkg")
    .ForEach def(file):
      file.Delete()

  with nuget_pack():
    .toolPath = "packages/NuGet.CommandLine.3.4.3/tools/NuGet.exe"
    .nuspecFile = "build/nuget/MarkEmbling.Utils.nuspec"
    .outputDirectory = package_path

  with nuget_pack():
    .toolPath = "packages/NuGet.CommandLine.3.4.3/tools/NuGet.exe"
    .nuspecFile = "build/nuget/MarkEmbling.Utils.Forms.nuspec"
    .outputDirectory = package_path

desc "Publishes the NuGet packages"
target publish, (package):
  with FileList(package_path):
    .Include("*.nupkg")
    .ForEach def(file):
      filename = Path.GetFileName(file.FullName)
      if prompt("Publish ${filename}...?"):
        exec("packages/NuGet.CommandLine.3.4.3/tools/NuGet.exe", file.FullName)
        #with nuget_push():
        #  .toolPath =  "packages/NuGet.CommandLine.3.4.3/tools/NuGet.exe"
        #  .packagePath = file.FullName

include "build_support.boo"

solution = "MarkEmbling.Utils.sln"
configuration = "release"
test_assembly = "MarkEmbling.Utils.Tests/bin/${configuration}/MarkEmbling.Utils.Tests.dll"
bin_path = "build/bin"
package_path = "build/nuget"

target default, (compile, test, prep):
  pass

desc "Compiles the solution"
target compile:
  msbuild(file: solution, configuration: configuration, version: "4.0")

desc "Executes the tests"
target test, (compile):
  with nunit(assembly: test_assembly, toolPath: "packages/NUnit.Runners.2.6.2/tools/nunit-console.exe")

desc "Copies the binaries to the 'build/bin' directory"
target prep, (compile, test):
  rmdir(bin_path)

  with FileList("MarkEmbling.Utils/bin/${configuration}"):
    .Include("*.{dll,exe,config}")
    .ForEach def(file):
      file.CopyToDirectory(bin_path)

  with FileList("MarkEmbling.Utils.Forms/bin/${configuration}"):
    .Include("*.{dll,exe,config}")
    .ForEach def(file):
      file.CopyToDirectory(bin_path)

desc "Creates the NuGet packages"
target package, (prep):
  with FileList(package_path):
    .Include("*.nupkg")
    .ForEach def(file):
      file.Delete()

  with nuget_pack():
    .toolPath = "packages/NuGet.CommandLine.3.4.3/tools/NuGet.exe"
    .nuspecFile = "build/nuget/MarkEmbling.Utils.nuspec"
    .outputDirectory = package_path

  with nuget_pack():
    .toolPath = "packages/NuGet.CommandLine.3.4.3/tools/NuGet.exe"
    .nuspecFile = "build/nuget/MarkEmbling.Utils.Forms.nuspec"
    .outputDirectory = package_path

desc "Publishes the NuGet packages"
target publish, (package):
  with FileList(package_path):
    .Include("*.nupkg")
    .ForEach def(file):
      filename = Path.GetFileName(file.FullName)
      if prompt("Publish ${filename}...?"):
        with nuget_push():
          .toolPath =  "packages/NuGet.CommandLine.3.4.3/tools/NuGet.exe"
          .packagePath = file.FullName


normalize directory separators before comparison so test works on all platforms

namespace UnityScript.Tests

import System.IO
import NUnit.Framework

[TestFixture]
class CommandLineOptionsTestFixture:

	[Test]
	def Defines():
		options = us.CommandLineOptions("-d:FOO", "--define:BAR")
		assert options.Defines == ["FOO", "BAR"]

	[Test]
	def SourceDirectoriesAreRecursivelyScanned():
		dir = CreateTempDirectory()

		files = "a.js", "Sub1/b.js", "Sub1/c.js", "Sub1/Sub2/d.js", "Sub1/Sub2/Sub3/Sub4/e.js"
		CreateFilesOn(dir, files)

		options = us.CommandLineOptions("-srcdir:${dir}")

		actualFiles = List of string()
		options.ForEachSourceFile(actualFiles.Add)

		Assert.AreEqual(
			array(Path.Combine(dir, file).Replace(char('/'), Path.DirectorySeparatorChar) for file in files),
			actualFiles.ToArray())

def CreateFilesOn(dir as string, files as string*):
	for file in files:
		fullName = Path.Combine(dir, file)
		Directory.CreateDirectory(Path.GetDirectoryName(fullName))
		File.WriteAllText(fullName, "")

def CreateTempDirectory():
	tmp = Path.GetTempFileName()
	File.Delete(tmp)
	Directory.CreateDirectory(tmp)
	return tmp

namespace UnityScript.Tests

import System.IO
import NUnit.Framework

[TestFixture]
class CommandLineOptionsTestFixture:

	[Test]
	def Defines():
		options = us.CommandLineOptions("-d:FOO", "--define:BAR")
		assert options.Defines == ["FOO", "BAR"]

	[Test]
	def SourceDirectoriesAreRecursivelyScanned():
		dir = CreateTempDirectory()

		files = "a.js", "Sub1/b.js", "Sub1/c.js", "Sub1/Sub2/d.js", "Sub1/Sub2/Sub3/Sub4/e.js"
		CreateFilesOn(dir, files)

		options = us.CommandLineOptions("-srcdir:${dir}")

		actualFiles = List of string()
		options.ForEachSourceFile(actualFiles.Add)

		Assert.AreEqual(
			array(Path.Combine(dir, file) for file in files),
			actualFiles.ToArray())

def CreateFilesOn(dir as string, files as string*):
	for file in files:
		fullName = Path.Combine(dir, file)
		Directory.CreateDirectory(Path.GetDirectoryName(fullName))
		File.WriteAllText(fullName, "")

def CreateTempDirectory():
	tmp = Path.GetTempFileName()
	File.Delete(tmp)
	Directory.CreateDirectory(tmp)
	return tmp


forgot this one in previous commit.

forgot this one in previous commit.

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

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

namespace Boo.Lang.Useful.Tests.Attributes

import System
import Boo.Lang.Useful.Attributes
import NUnit.Framework

[TestFixture]
class OnceAttributeTestFixture(AbstractAttributeTestFixture):
"""
@author Sorin Ionescu (sorin.ionescu@gmail.com)
"""
	private class Math:
		[once]
		static def Square(value as int):
			return value**2

		[once]
		def Cube(value as int):
			return value**3

	// TODO: test attribute expansion with AbstractAttributeTestFixture

	[Test]
	def TestStaticOnce():
		assert 100 == Math.Square(10)
		assert 100 == Math.Square(20)

	[Test]
	def TestInstanceOnce():
		m1 = Math()
		m2 = Math()

		assert 1000 == m1.Cube(10)
		assert 1000 == m1.Cube(20)
		assert 27 == m2.Cube(3)
		assert 27 == m2.Cube(10)

	[Test]
	def TestModuleMethod():
		code = """
import Useful.Attributes

[once]
def foo():
	return 3
"""

		expected = """
import Useful.Attributes

[System.Runtime.CompilerServices.CompilerGlobalScopeAttribute]
public final transient class CodeModule(System.Object):

	public static def foo() as System.Int32:
		if not CodeModule.___foo_cached:
			System.Threading.Monitor.Enter(CodeModule.___foo_lock)
			try:
				if not CodeModule.___foo_cached:
					CodeModule.___foo_returnValue = 3
					CodeModule.___foo_cached = true
			ensure:
				System.Threading.Monitor.Exit(CodeModule.___foo_lock)
		return CodeModule.___foo_returnValue

	private static ___foo_cached as System.Boolean

	private static ___foo_lock as System.Object

	private def constructor():
		super()

	public static def constructor():
		CodeModule.___foo_lock = object()

	private static ___foo_returnValue as System.Int32
"""
		RunTestCase(expected, code)

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

namespace Boo.Lang.Useful.Tests.Attributes

import System
import Boo.Lang.Useful.Attributes
import NUnit.Framework

[TestFixture]
class OnceAttributeTestFixture(AbstractAttributeTestFixture):
"""
@author Sorin Ionescu (sorin.ionescu@gmail.com)
"""
	private class Math:
		[once]
		static def Square(value as int):
			return value**2

		[once]
		def Cube(value as int):
			return value**3

	// TODO: test attribute expansion with AbstractAttributeTestFixture

	[Test]
	def TestStaticOnce():
		assert 100 == Math.Square(10)
		assert 100 == Math.Square(20)

	[Test]
	def TestInstanceOnce():
		m1 = Math()
		m2 = Math()

		assert 1000 == m1.Cube(10)
		assert 1000 == m1.Cube(20)
		assert 27 == m2.Cube(3)
		assert 27 == m2.Cube(10)

	[Test]
	def TestModuleMethod():
		code = """
import Useful.Attributes

[once]
def foo():
	return 3
"""

		expected = """
import Useful.Attributes

[Boo.Lang.ModuleAttribute]
public final transient class CodeModule(System.Object):

	public static def foo() as System.Int32:
		if not CodeModule.___foo_cached:
			System.Threading.Monitor.Enter(CodeModule.___foo_lock)
			try:
				if not CodeModule.___foo_cached:
					CodeModule.___foo_returnValue = 3
					CodeModule.___foo_cached = true
			ensure:
				System.Threading.Monitor.Exit(CodeModule.___foo_lock)
		return CodeModule.___foo_returnValue

	private static ___foo_cached as System.Boolean

	private static ___foo_lock as System.Object

	private def constructor():
		super()

	public static def constructor():
		CodeModule.___foo_lock = object()

	private static ___foo_returnValue as System.Int32
"""
		RunTestCase(expected, code)


event raise method test case

event raise method test case

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

import System
import System.Reflection
import NUnit.Framework

class Button:
	event Click as EventHandler

def CheckEventMethod(expectedName, method as MethodInfo):
	Assert.IsNotNull(method, expectedName)
	Assert.AreEqual(expectedName, method.Name)
	Assert.AreEqual(1, len(method.GetParameters()))
	Assert.AreSame(EventHandler, method.GetParameters()[0].ParameterType)
	Assert.AreSame(void, method.ReturnType)
	Assert.IsTrue(method.IsSpecialName, "IsSpecialName")
	Assert.IsTrue(method.IsPublic, "IsPublic")

type = Button
eventInfo = type.GetEvent("Click")
Assert.IsNotNull(eventInfo, "Click")
Assert.AreSame(EventHandler, eventInfo.EventHandlerType)

CheckEventMethod("add_Click", eventInfo.GetAddMethod())
CheckEventMethod("remove_Click", eventInfo.GetRemoveMethod())

raiseMethod = eventInfo.GetRaiseMethod()
assert raiseMethod is not null
assert raiseMethod.ReturnType is void
assert raiseMethod.IsPublic
assert raiseMethod.IsSpecialName
assert 2 == len(raiseMethod.GetParameters())
assert raiseMethod.GetParameters()[0] is object
assert raiseMethod.GetParameters()[1] is EventArgs


unreserving 'success' and 'retry'

unreserving 'success' and 'retry'

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

"""
The classes in this module model the entire AST for the language.

The actual AST classes and supporting modules are generated
by a boo script.
"""
namespace Boo.Ast

class CompileUnit(Node):
	Modules as ModuleCollection

enum TypeMemberModifiers:
	None = 0
	Private = 1
	Internal = 2
	Protected = 4
	Public = 8
	Transient = 16
	Static = 32
	Final = 64
	Virtual = 128
	Override = 256
	Abstract = 512
	Partial = 1024
	VisibilityMask = 15

enum MethodImplementationFlags:
	None = 0
	Runtime = 1

enum ParameterModifiers:
	None = 0
	Val = 0
	Ref = 1

abstract class TypeMember(Node, INodeWithAttributes):
	Modifiers as TypeMemberModifiers
	Name as string
	Attributes as AttributeCollection

class ExplicitMemberInfo(Node):
	InterfaceType as SimpleTypeReference

[collection(TypeMember)]
class TypeMemberCollection:
	pass

abstract class TypeReference(Node):
	pass

class SimpleTypeReference(TypeReference):
	Name as string

class ArrayTypeReference(TypeReference):
	ElementType as TypeReference
	Rank as IntegerLiteralExpression

class CallableTypeReference(TypeReference):
	Parameters as ParameterDeclarationCollection
	ReturnType as TypeReference

class GenericTypeReference(SimpleTypeReference):
	GenericArguments as TypeReferenceCollection

[collection(TypeReference)]
class TypeReferenceCollection:
	pass

class CallableDefinition(TypeMember, INodeWithParameters):
	Parameters as ParameterDeclarationCollection
	ReturnType as TypeReference
	ReturnTypeAttributes as AttributeCollection

abstract class TypeDefinition(TypeMember):
	Members as TypeMemberCollection
	BaseTypes as TypeReferenceCollection

[collection(TypeDefinition)]
class TypeDefinitionCollection:
	pass

class NamespaceDeclaration(Node):
	Name as string

class Import(Node):
	Namespace as string
	AssemblyReference as ReferenceExpression
	Alias as ReferenceExpression

[collection(Import)]
class ImportCollection:
	pass

class Module(TypeDefinition):
	Namespace as NamespaceDeclaration
	Imports as ImportCollection
	[auto]
	Globals as Block
	AssemblyAttributes as AttributeCollection

[collection(Module)]
class ModuleCollection:
	pass

class ClassDefinition(TypeDefinition):
	pass

class StructDefinition(TypeDefinition):
	pass

class InterfaceDefinition(TypeDefinition):
	pass

class EnumDefinition(TypeDefinition):
	pass

class EnumMember(TypeMember):
	Initializer as IntegerLiteralExpression

class Field(TypeMember):
	Type as TypeReference
	Initializer as Expression

class Property(TypeMember, INodeWithParameters, IExplicitMember):
	Parameters as ParameterDeclarationCollection
	Getter as Method
	Setter as Method
	Type as TypeReference
	ExplicitInfo as ExplicitMemberInfo

class Event(TypeMember):
	Add as Method
	Remove as Method
	Raise as Method
	Type as TypeReference

class Local(Node):
	Name as string

[collection(Local)]
class LocalCollection:
	pass

class CallableBlockExpression(Expression, INodeWithParameters):
	Parameters as ParameterDeclarationCollection
	ReturnType as TypeReference
	[auto]
	Body as Block

class Method(CallableDefinition, IExplicitMember):
	[auto]
	Body as Block
	Locals as LocalCollection
	ImplementationFlags as MethodImplementationFlags
	ExplicitInfo as ExplicitMemberInfo

class Constructor(Method):
	pass

class Destructor(Method):
	pass

class ParameterDeclaration(Node, INodeWithAttributes):
	Name as string
	Type as TypeReference
	Modifiers as ParameterModifiers
	Attributes as AttributeCollection

[collection(ParameterDeclaration)]
class ParameterDeclarationCollection:
	pass

class Declaration(Node):
	Name as string
	Type as TypeReference

[collection(Declaration)]
class DeclarationCollection:
	pass

class Attribute(Node, INodeWithArguments):
	Name as string
	Arguments as ExpressionCollection
	NamedArguments as ExpressionPairCollection

[collection(Attribute)]
class AttributeCollection:
	pass

enum StatementModifierType:
	Uninitialized
	If
	Unless
	While

class StatementModifier(Node):
	Type as StatementModifierType
	Condition as Expression

abstract class Statement(Node):
	Modifier as StatementModifier

class GotoStatement(Statement):
	Label as ReferenceExpression

class LabelStatement(Statement):
	Name as string

class Block(Statement):
	Statements as StatementCollection

[collection(Statement)]
class StatementCollection:
	pass

class DeclarationStatement(Statement):
	Declaration as Declaration
	Initializer as Expression

class MacroStatement(Statement):
	Name as string
	Arguments as ExpressionCollection

	[auto]
	Block as Block

class TryStatement(Statement):
	[auto]
	ProtectedBlock as Block
	ExceptionHandlers as ExceptionHandlerCollection
	EnsureBlock as Block

class ExceptionHandler(Node):
	Declaration as Declaration

	[auto]
	Block as Block

[collection(ExceptionHandler)]
class ExceptionHandlerCollection:
	pass

class IfStatement(Statement):
	Condition as Expression
	TrueBlock as Block
	FalseBlock as Block

class UnlessStatement(Statement):
	Condition as Expression

	[auto]
	Block as Block

class ForStatement(Statement):
	Declarations as DeclarationCollection
	Iterator as Expression

	[auto]
	Block as Block

class WhileStatement(Statement):
	Condition as Expression

	[auto]
	Block as Block

class GivenStatement(Statement):
	Expression as Expression
	WhenClauses as WhenClauseCollection
	OtherwiseBlock as Block

class WhenClause(Node):
	Condition as Expression

	[auto]
	Block as Block

[collection(WhenClause)]
class WhenClauseCollection:
	pass

class BreakStatement(Statement):
	pass

class ContinueStatement(Statement):
	pass

class ReturnStatement(Statement):
	Expression as Expression

class YieldStatement(Statement):
	Expression as Expression

class RaiseStatement(Statement):
	Exception as Expression

class UnpackStatement(Statement):
	Declarations as DeclarationCollection
	Expression as Expression

class ExpressionStatement(Statement):
	[LexicalInfo]
	Expression as Expression

abstract class Expression(Node):
	pass

[collection(Expression)]
class ExpressionCollection:
	pass

[ignore]
class OmittedExpression(Expression):
	pass

class ExpressionPair(Node):
	First as Expression
	Second as Expression

[collection(ExpressionPair)]
class ExpressionPairCollection:
	pass

class MethodInvocationExpression(Expression, INodeWithArguments):
	Target as Expression
	Arguments as ExpressionCollection
	NamedArguments as ExpressionPairCollection

enum BinaryOperatorType:
	None
	Addition
	Subtraction
	Multiply
	Division
	Modulus
	Exponentiation
	LessThan
	LessThanOrEqual
	GreaterThan
	GreaterThanOrEqual
	Equality
	Inequality
	Match
	NotMatch
	Assign
	InPlaceAddition
	InPlaceSubtraction
	InPlaceMultiply
	InPlaceDivision
	InPlaceBitwiseAnd
	InPlaceBitwiseOr
	ReferenceEquality
	ReferenceInequality
	TypeTest
	Member
	NotMember
	Or
	And
	BitwiseOr
	BitwiseAnd
	ExclusiveOr
	InPlaceExclusiveOr
	ShiftLeft
	InPlaceShiftLeft
	ShiftRight
	InPlaceShiftRight

enum UnaryOperatorType:
	None
	UnaryNegation
	Increment
	Decrement
	PostIncrement
	PostDecrement
	LogicalNot
	Explode
	OnesComplement

class UnaryExpression(Expression):
	Operator as UnaryOperatorType
	Operand as Expression

class BinaryExpression(Expression):
	Operator as BinaryOperatorType
	Left as Expression
	Right as Expression

class ConditionalExpression(Expression):
	Condition as Expression
	TrueValue as Expression
	FalseValue as Expression

class ReferenceExpression(Expression):
	Name as string

class MemberReferenceExpression(ReferenceExpression):
	Target as Expression

class GenericReferenceExpression(Expression):
	Target as Expression
	GenericArguments as TypeReferenceCollection

abstract class LiteralExpression(Expression):
	pass

class AstLiteralExpression(LiteralExpression):
	Node as Node

class StringLiteralExpression(LiteralExpression):
	Value as string

class CharLiteralExpression(StringLiteralExpression):
	pass

class TimeSpanLiteralExpression(LiteralExpression):
	Value as System.TimeSpan

class IntegerLiteralExpression(LiteralExpression):
	Value as long
	IsLong as bool

class DoubleLiteralExpression(LiteralExpression):
	Value as double
	IsSingle as bool

class NullLiteralExpression(LiteralExpression):
	pass

class SelfLiteralExpression(LiteralExpression):
	pass

class SuperLiteralExpression(LiteralExpression):
	pass

class BoolLiteralExpression(LiteralExpression):
	Value as bool

class RELiteralExpression(LiteralExpression):
	Value as string

class ExpressionInterpolationExpression(Expression):
	Expressions as ExpressionCollection

class HashLiteralExpression(LiteralExpression):
	Items as ExpressionPairCollection

class ListLiteralExpression(LiteralExpression):
	Items as ExpressionCollection

class ArrayLiteralExpression(ListLiteralExpression):
	Type as ArrayTypeReference

class GeneratorExpression(Expression):
	Expression as Expression
	Declarations as DeclarationCollection
	Iterator as Expression
	Filter as StatementModifier

class ExtendedGeneratorExpression(Expression):
	Items as GeneratorExpressionCollection

[collection(GeneratorExpression)]
class GeneratorExpressionCollection:
	pass

class Slice(Node):
	Begin as Expression
	End as Expression
	Step as Expression

[collection(Slice)]
class SliceCollection:
	pass

class SlicingExpression(Expression):
	Target as Expression
	Indices as SliceCollection

class TryCastExpression(Expression):
	Target as Expression
	Type as TypeReference

class CastExpression(Expression):
	Target as Expression
	Type as TypeReference

class TypeofExpression(Expression):
	Type as TypeReference

"""
The classes in this module model the entire AST for the language.

The actual AST classes and supporting modules are generated
by a boo script.
"""
namespace Boo.Ast

class CompileUnit(Node):
	Modules as ModuleCollection

enum TypeMemberModifiers:
	None = 0
	Private = 1
	Internal = 2
	Protected = 4
	Public = 8
	Transient = 16
	Static = 32
	Final = 64
	Virtual = 128
	Override = 256
	Abstract = 512
	Partial = 1024
	VisibilityMask = 15

enum MethodImplementationFlags:
	None = 0
	Runtime = 1

enum ParameterModifiers:
	None = 0
	Val = 0
	Ref = 1

abstract class TypeMember(Node, INodeWithAttributes):
	Modifiers as TypeMemberModifiers
	Name as string
	Attributes as AttributeCollection

class ExplicitMemberInfo(Node):
	InterfaceType as SimpleTypeReference

[collection(TypeMember)]
class TypeMemberCollection:
	pass

abstract class TypeReference(Node):
	pass

class SimpleTypeReference(TypeReference):
	Name as string

class ArrayTypeReference(TypeReference):
	ElementType as TypeReference
	Rank as IntegerLiteralExpression

class CallableTypeReference(TypeReference):
	Parameters as ParameterDeclarationCollection
	ReturnType as TypeReference

class GenericTypeReference(SimpleTypeReference):
	GenericArguments as TypeReferenceCollection

[collection(TypeReference)]
class TypeReferenceCollection:
	pass

class CallableDefinition(TypeMember, INodeWithParameters):
	Parameters as ParameterDeclarationCollection
	ReturnType as TypeReference
	ReturnTypeAttributes as AttributeCollection

abstract class TypeDefinition(TypeMember):
	Members as TypeMemberCollection
	BaseTypes as TypeReferenceCollection

[collection(TypeDefinition)]
class TypeDefinitionCollection:
	pass

class NamespaceDeclaration(Node):
	Name as string

class Import(Node):
	Namespace as string
	AssemblyReference as ReferenceExpression
	Alias as ReferenceExpression

[collection(Import)]
class ImportCollection:
	pass

class Module(TypeDefinition):
	Namespace as NamespaceDeclaration
	Imports as ImportCollection
	[auto]
	Globals as Block
	AssemblyAttributes as AttributeCollection

[collection(Module)]
class ModuleCollection:
	pass

class ClassDefinition(TypeDefinition):
	pass

class StructDefinition(TypeDefinition):
	pass

class InterfaceDefinition(TypeDefinition):
	pass

class EnumDefinition(TypeDefinition):
	pass

class EnumMember(TypeMember):
	Initializer as IntegerLiteralExpression

class Field(TypeMember):
	Type as TypeReference
	Initializer as Expression

class Property(TypeMember, INodeWithParameters, IExplicitMember):
	Parameters as ParameterDeclarationCollection
	Getter as Method
	Setter as Method
	Type as TypeReference
	ExplicitInfo as ExplicitMemberInfo

class Event(TypeMember):
	Add as Method
	Remove as Method
	Raise as Method
	Type as TypeReference

class Local(Node):
	Name as string

[collection(Local)]
class LocalCollection:
	pass

class CallableBlockExpression(Expression, INodeWithParameters):
	Parameters as ParameterDeclarationCollection
	ReturnType as TypeReference
	[auto]
	Body as Block

class Method(CallableDefinition, IExplicitMember):
	[auto]
	Body as Block
	Locals as LocalCollection
	ImplementationFlags as MethodImplementationFlags
	ExplicitInfo as ExplicitMemberInfo

class Constructor(Method):
	pass

class Destructor(Method):
	pass

class ParameterDeclaration(Node, INodeWithAttributes):
	Name as string
	Type as TypeReference
	Modifiers as ParameterModifiers
	Attributes as AttributeCollection

[collection(ParameterDeclaration)]
class ParameterDeclarationCollection:
	pass

class Declaration(Node):
	Name as string
	Type as TypeReference

[collection(Declaration)]
class DeclarationCollection:
	pass

class Attribute(Node, INodeWithArguments):
	Name as string
	Arguments as ExpressionCollection
	NamedArguments as ExpressionPairCollection

[collection(Attribute)]
class AttributeCollection:
	pass

enum StatementModifierType:
	Uninitialized
	If
	Unless
	While

class StatementModifier(Node):
	Type as StatementModifierType
	Condition as Expression

abstract class Statement(Node):
	Modifier as StatementModifier

class GotoStatement(Statement):
	Label as ReferenceExpression

class LabelStatement(Statement):
	Name as string

class Block(Statement):
	Statements as StatementCollection

[collection(Statement)]
class StatementCollection:
	pass

class DeclarationStatement(Statement):
	Declaration as Declaration
	Initializer as Expression

class MacroStatement(Statement):
	Name as string
	Arguments as ExpressionCollection

	[auto]
	Block as Block

class TryStatement(Statement):
	[auto]
	ProtectedBlock as Block
	ExceptionHandlers as ExceptionHandlerCollection
	SuccessBlock as Block
	EnsureBlock as Block

class ExceptionHandler(Node):
	Declaration as Declaration

	[auto]
	Block as Block

[collection(ExceptionHandler)]
class ExceptionHandlerCollection:
	pass

class IfStatement(Statement):
	Condition as Expression
	TrueBlock as Block
	FalseBlock as Block

class UnlessStatement(Statement):
	Condition as Expression

	[auto]
	Block as Block

class ForStatement(Statement):
	Declarations as DeclarationCollection
	Iterator as Expression

	[auto]
	Block as Block

class WhileStatement(Statement):
	Condition as Expression

	[auto]
	Block as Block

class GivenStatement(Statement):
	Expression as Expression
	WhenClauses as WhenClauseCollection
	OtherwiseBlock as Block

class WhenClause(Node):
	Condition as Expression

	[auto]
	Block as Block

[collection(WhenClause)]
class WhenClauseCollection:
	pass

class BreakStatement(Statement):
	pass

class ContinueStatement(Statement):
	pass

class RetryStatement(Statement):
	pass

class ReturnStatement(Statement):
	Expression as Expression

class YieldStatement(Statement):
	Expression as Expression

class RaiseStatement(Statement):
	Exception as Expression

class UnpackStatement(Statement):
	Declarations as DeclarationCollection
	Expression as Expression

class ExpressionStatement(Statement):
	[LexicalInfo]
	Expression as Expression

abstract class Expression(Node):
	pass

[collection(Expression)]
class ExpressionCollection:
	pass

[ignore]
class OmittedExpression(Expression):
	pass

class ExpressionPair(Node):
	First as Expression
	Second as Expression

[collection(ExpressionPair)]
class ExpressionPairCollection:
	pass

class MethodInvocationExpression(Expression, INodeWithArguments):
	Target as Expression
	Arguments as ExpressionCollection
	NamedArguments as ExpressionPairCollection

enum BinaryOperatorType:
	None
	Addition
	Subtraction
	Multiply
	Division
	Modulus
	Exponentiation
	LessThan
	LessThanOrEqual
	GreaterThan
	GreaterThanOrEqual
	Equality
	Inequality
	Match
	NotMatch
	Assign
	InPlaceAddition
	InPlaceSubtraction
	InPlaceMultiply
	InPlaceDivision
	InPlaceBitwiseAnd
	InPlaceBitwiseOr
	ReferenceEquality
	ReferenceInequality
	TypeTest
	Member
	NotMember
	Or
	And
	BitwiseOr
	BitwiseAnd
	ExclusiveOr
	InPlaceExclusiveOr
	ShiftLeft
	InPlaceShiftLeft
	ShiftRight
	InPlaceShiftRight

enum UnaryOperatorType:
	None
	UnaryNegation
	Increment
	Decrement
	PostIncrement
	PostDecrement
	LogicalNot
	Explode
	OnesComplement

class UnaryExpression(Expression):
	Operator as UnaryOperatorType
	Operand as Expression

class BinaryExpression(Expression):
	Operator as BinaryOperatorType
	Left as Expression
	Right as Expression

class ConditionalExpression(Expression):
	Condition as Expression
	TrueValue as Expression
	FalseValue as Expression

class ReferenceExpression(Expression):
	Name as string

class MemberReferenceExpression(ReferenceExpression):
	Target as Expression

class GenericReferenceExpression(Expression):
	Target as Expression
	GenericArguments as TypeReferenceCollection

abstract class LiteralExpression(Expression):
	pass

class AstLiteralExpression(LiteralExpression):
	Node as Node

class StringLiteralExpression(LiteralExpression):
	Value as string

class CharLiteralExpression(StringLiteralExpression):
	pass

class TimeSpanLiteralExpression(LiteralExpression):
	Value as System.TimeSpan

class IntegerLiteralExpression(LiteralExpression):
	Value as long
	IsLong as bool

class DoubleLiteralExpression(LiteralExpression):
	Value as double
	IsSingle as bool

class NullLiteralExpression(LiteralExpression):
	pass

class SelfLiteralExpression(LiteralExpression):
	pass

class SuperLiteralExpression(LiteralExpression):
	pass

class BoolLiteralExpression(LiteralExpression):
	Value as bool

class RELiteralExpression(LiteralExpression):
	Value as string

class ExpressionInterpolationExpression(Expression):
	Expressions as ExpressionCollection

class HashLiteralExpression(LiteralExpression):
	Items as ExpressionPairCollection

class ListLiteralExpression(LiteralExpression):
	Items as ExpressionCollection

class ArrayLiteralExpression(ListLiteralExpression):
	Type as ArrayTypeReference

class GeneratorExpression(Expression):
	Expression as Expression
	Declarations as DeclarationCollection
	Iterator as Expression
	Filter as StatementModifier

class ExtendedGeneratorExpression(Expression):
	Items as GeneratorExpressionCollection

[collection(GeneratorExpression)]
class GeneratorExpressionCollection:
	pass

class Slice(Node):
	Begin as Expression
	End as Expression
	Step as Expression

[collection(Slice)]
class SliceCollection:
	pass

class SlicingExpression(Expression):
	Target as Expression
	Indices as SliceCollection

class TryCastExpression(Expression):
	Target as Expression
	Type as TypeReference

class CastExpression(Expression):
	Target as Expression
	Type as TypeReference

class TypeofExpression(Expression):
	Type as TypeReference


make compiler initialization compatible with bundled distributions

namespace BooJs.Compiler.Pipelines

from System import InvalidOperationException, ArgumentNullException
from System.Reflection import Assembly
from System.Collections.Generic import HashSet

from Boo.Lang.Environments import DeferredEnvironment
from Boo.Lang.Compiler import BooCompiler, CompilerParameters
from Boo.Lang.Compiler.Ast import *
from Boo.Lang.Compiler.Services import UniqueNameProvider as BooUniqueNameProvider
from Boo.Lang.Compiler.TypeSystem import TypeSystemServices
from Boo.Lang.Compiler.TypeSystem.Services import DowncastPermissions

from BooJs.Compiler import UniqueNameProvider, CompilerContext, TypeSystem as BooJsTypeSystem

class BooJsCompiler(BooCompiler):
""" Implements our own compiler façade instead of using the original one.
"""
    def constructor(params as CompilerParameters):
        super(params)

    new def Run(unit as CompileUnit):
        if not unit:
            raise ArgumentNullException("compileUnit");
        if not Parameters.Pipeline:
            raise InvalidOperationException(Boo.Lang.Resources.StringResources.BooC_CantRunWithoutPipeline)

        ctxt = CompilerContext(Parameters, unit)
        Parameters.Pipeline.Run(ctxt)

        return ctxt

    new def Run():
        return Run(CompileUnit())

def newBooJsCompiler():
    return newBooJsCompiler(SaveJs())

def newBooJsCompiler(pipeline as Boo.Lang.Compiler.CompilerPipeline):
    # Register our custom type system provider
    params = BooJs.Compiler.CompilerParameters(BooJsTypeSystem.ReflectionProvider.SharedTypeSystemProvider, false)
    # Setup the environment by setting our customized type system services
    params.Environment = DeferredEnvironment() {
        TypeSystemServices: { BooJsTypeSystem.TypeSystemServices() },
        DowncastPermissions: { BooJsTypeSystem.DowncastPermissions() },
        BooUniqueNameProvider: { UniqueNameProvider() }
    }

    # When running from a *bundle* (ilrepack, mkbundle, ...) the namespaces may be already loaded
    asm = Assembly.GetExecutingAssembly()
    namespaces = HashSet[of string]()
    for type in asm.GetTypes():
        namespaces.Add(type.Namespace)

    # Load language runtime and pattern matching assemblies by default
    for ns in ('BooJs.Lang', 'Boo.Lang.PatternMatching'):
        if ns not in namespaces:
            params.References.Add(params.LoadAssembly(ns))

    params.Pipeline = pipeline
    return BooJsCompiler(params)

namespace BooJs.Compiler.Pipelines

from System import InvalidOperationException, ArgumentNullException
from Boo.Lang.Environments import DeferredEnvironment
from Boo.Lang.Compiler import BooCompiler, CompilerParameters
from Boo.Lang.Compiler.Ast import *
from Boo.Lang.Compiler.Services import UniqueNameProvider as BooUniqueNameProvider
from Boo.Lang.Compiler.TypeSystem import TypeSystemServices
from Boo.Lang.Compiler.TypeSystem.Services import DowncastPermissions

from BooJs.Compiler import UniqueNameProvider, CompilerContext, TypeSystem as BooJsTypeSystem

class BooJsCompiler(BooCompiler):
""" Implements our own compiler façade instead of using the original one.
"""
    def constructor(params as CompilerParameters):
        super(params)

    new def Run(unit as CompileUnit):
        if not unit:
            raise ArgumentNullException("compileUnit");
        if not Parameters.Pipeline:
            raise InvalidOperationException(Boo.Lang.Resources.StringResources.BooC_CantRunWithoutPipeline)

        ctxt = CompilerContext(Parameters, unit)
        Parameters.Pipeline.Run(ctxt)

        return ctxt

    new def Run():
        return Run(CompileUnit())

def newBooJsCompiler():
    return newBooJsCompiler(SaveJs())

def newBooJsCompiler(pipeline as Boo.Lang.Compiler.CompilerPipeline):
    # Register our custom type system provider
    params = BooJs.Compiler.CompilerParameters(BooJsTypeSystem.ReflectionProvider.SharedTypeSystemProvider, false)
    # Setup the environment by setting our customized type system services
    params.Environment = DeferredEnvironment() {
        TypeSystemServices: { BooJsTypeSystem.TypeSystemServices() },
        DowncastPermissions: { BooJsTypeSystem.DowncastPermissions() },
        BooUniqueNameProvider: { UniqueNameProvider() }
    }

    # Load language runtime assemblies
    params.References.Add(params.LoadAssembly('BooJs.Lang'))
    # Load Boo.Lang.PatternMatching assembly (we provide access to it by default)
    params.References.Add(params.LoadAssembly('Boo.Lang.PatternMatching'))

    params.Pipeline = pipeline
    return BooJsCompiler(params)