Fixed regexp bug and added support for hash style object notation

namespace BooJs.Compiler.Steps

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

import BooJs.Compiler.SourceMap

class BooJsPrinterVisitor(Visitors.TextEmitter):

    _context as CompilerContext

    srcmap as MapBuilder

    def constructor(writer as System.IO.TextWriter):
        super(writer)
        IndentText = '  '

        srcmap = MapBuilder()

    def Initialize(context as CompilerContext):
        _context = context

    def Print(ast as CompileUnit):
        OnCompileUnit(ast)

        WriteLine '//@ sourceMappingURL=map.js.map'
        print 'var map = ' + srcmap.ToString()

    def WriteLine():
        srcmap.NewLine()
        super.WriteLine()

    def Write(str as string):
        srcmap.Column += str.Length
        super.Write(str)

    def Map(node as Node):
    """ Maps the given node lexical info to the current position in the generated file
    """
        srcmap.Segment(node)

    def OnBoolLiteralExpression(node as BoolLiteralExpression):
        Write( ('true' if node.Value else 'false') )

    def OnNullLiteralExpression(node as NullLiteralExpression):
        Write 'null'

    def OnModule(node as Module):

        # HACK: ProcessMethodBodies step is too complex so we opt for reversing some
        #       of the stuff it does instead of modifying it. Here we just ignore
        #       any modules it generates to support 'dynamic' features at runtime
        if node.Name == 'CompilerGenerated':
            WriteLine
            Write '/*** CompilerGenerated ***********************'
            WriteLine

        Visit(node.Namespace)

        if node.Imports.Count > 0:
            Visit(node.Imports)
            WriteLine()

        for member in node.Members:
            Visit(member)
            WriteLine()

        if node.Globals:
            Visit(node.Globals.Statements)

        if node.Name == 'CompilerGenerated':
            WriteLine '*** /CompilerGenerated **********************/'

    def WriteLocals(locals as LocalCollection):
    """ Write locals ensuring they are not repeated """
        found = []
        for local in locals:
            continue if local.Name == '$locals'
            continue if local.Name in found
            found.Push(local.Name)
            Visit local

    def OnMethod(m as Method):

        # Types are already resolved so we can just check if it was flagged as a generator
        entity as TypeSystem.Internal.InternalMethod = m.Entity
        if entity.IsGenerator:
            print 'Generator'

        if m.IsRuntime:
            WriteIndented('// runtime')
            WriteLine()

        if /^\$\w+\$closure\$\d+/.IsMatch(m.Name):
            print 'Skipping closure method', m.Name
            return

        # HACK!!! Find assignments of $locals.$<name> to define these as local variables
        # TODO: Improve the algorithm to support all cases
        # TODO: Move to a separate step
        def FindClosureLocals(block as Block):
            for st in block.Statements:
                if st isa Block:
                    FindClosureLocals(st)
                elif st isa Method:
                    FindClosureLocals((st as Method).Body)
                elif st isa BlockExpression:
                    FindClosureLocals((st as BlockExpression).Body)
                elif st isa ExpressionStatement:
                    es = st as ExpressionStatement
                    if es.Expression isa BinaryExpression:
                        be = es.Expression as BinaryExpression
                        if /^\$locals\.\$/.IsMatch(be.Left.ToString()):
                            str = be.Left.ToString()
                            parts = str.Split(char('.'))
                            local = Local()
                            local.Name = parts[1][1:]
                            m.Locals.Add(local)

        FindClosureLocals(m.Body)

        # HACK: If we detect the Main method we just output its statements
        if m.Name == 'Main':
            WriteLocals(m.Locals)
            Visit m.Body
            return

        WriteCallableDefinitionHeader('function ', m)
        WriteOpenBrace
        WriteLocals(m.Locals)
        Visit m.Body
        WriteCloseBrace

    def OnSlicingExpression(node as SlicingExpression):
        if len(node.Indices) != 1:
            raise 'Only one index is supported when slicing'

        Visit node.Target
        Write '['
        Visit node.Indices[0]
        Write ']'

    def OnUnpackStatement(node as UnpackStatement):
        WriteLine 'var __unpack;'

        Write '__unpack = '
        Visit node.Expression

        idx = 0
        for decl in node.Declarations:
            Write ", $(decl.Name) = __unpack[$idx]"
            idx++

        WriteLine ';'

    def OnBlockExpression(node as BlockExpression):
    """ Javascript has native support for closures thus the conversion is very simple.
    """
        Write 'function('
        if len(node.Parameters):
            WriteCommaSeparatedList(node.Parameters)
        Write ')'
        if node.Body.IsEmpty:
            Write '{}'
        elif len(node.Body.Statements) == 1 \
        and  len(node.Body.Statements[0].ToString()) < 30:
            # TODO: When it's just one statement we should inject a return if not present
            #       Seems like Boo already does that :)
            Write '{ '
            # TODO: Avoid generating a new line
            Visit node.Body.Statements[0]
            Write ' }'
        else:
            WriteOpenBrace
            Visit(node.Body.Statements)
            WriteCloseBrace false

    def WriteOpenBrace():
        Write '{'
        WriteLine
        Indent
        WriteIndented

    def WriteCloseBrace(cr as bool):
        Dedent
        WriteIndented
        Write '}'
        WriteLine if cr
        WriteLine if cr

    def WriteCloseBrace():
        WriteCloseBrace(true)

    def WriteAnnotation(str as string):
        lines = str.Split("\n"[0])
        if len(lines) == 1:
            Write '/** ' + str + ' */'
        else:
            WriteLine '/**'
            for ln in lines:
                WriteIndented ' * '
                Write ln
                WriteLine
            WriteIndented ' */'

    def OnLocal(node as Local):
        # HACK: We should find a better way to compare the type. If it matches
        #       the special global type (ie: jQuery as global) then we avoid defining
        #       it, which would shadow the global variable
        #ilocal = node.Entity as Boo.Lang.Compiler.TypeSystem.ITypedEntity
        #if ilocal.Type.ToString() == 'Boojs.Lang.global':
        #    return

        entity = node.Entity as TypeSystem.ITypedEntity

        # TODO: Add proper type annotations
        WriteIndented
        WriteAnnotation "@type {$(entity.Type)}"
        Write " var $(node.Name);"
        WriteLine

    def OnReferenceExpression(node as ReferenceExpression):
        # TODO: Check name for invalid chars?
        Map node
        Write node.Name

    def OnDeclarationStatement(node as DeclarationStatement):
        WriteIndented 'var '
        Map node
        Write node.Declaration.Name
        if node.Initializer:
            Write ' = '
            Visit node.Initializer
        WriteLine ';'

    def OnIfStatement(node as IfStatement):

        last_had_braces = false

        def IsElIf(block as Block):
            return false if not block
            return false if block.Statements.Count != 1
            return block.Statements[0] isa IfStatement

        def WriteCondBlock(keyword, node as IfStatement):
            Write keyword + ' ('
            Visit node.Condition
            Write ') '
            if len(node.TrueBlock.Statements):
                WriteOpenBrace
                last_had_braces = true
                Visit(node.TrueBlock.Statements)
            else:
                WritePass

        WriteIndented
        WriteCondBlock('if', node)

        block = node.FalseBlock
        while IsElIf(block):
            stmt as IfStatement = block.Statements[0]
            if last_had_braces:
                WriteCloseBrace false
                WriteCondBlock(' else if', stmt)
            else:
                WriteCondBlock('else if', stmt)
            block = stmt.FalseBlock

        if block:
            if last_had_braces:
                last_had_braces = false
                WriteCloseBrace false
                WriteIndented ' else '
            else:
                WriteIndented 'else '

            if len(block.Statements) > 1:
                WriteOpenBrace
                last_had_braces = true
                Visit block.Statements
            elif len(block.Statements) == 1:
                Visit block.Statements
            else:
                Write '{}'
                WriteLine

        WriteCloseBrace if last_had_braces

    def WritePass():
        WriteLine '"pass";'

    def OnConditionalExpression(node as ConditionalExpression):
    """ Convert to the ternary operator.
            (10 if true else 20)  -->  true ? 10 : 20
    """
        WriteWithOptionalParens node.Condition
        Write ' ? '
        WriteWithOptionalParens node.TrueValue
        Write ' : '
        WriteWithOptionalParens node.FalseValue

    def WriteWithOptionalParens(node as Node):
        parens = NeedsParensAround(node)
        if parens:
            WriteWithParens(node)
        else:
            Visit node

    def WriteWithParens(node as Node):
        Write '('
        Visit node
        Write ')'

    def OnTryStatement(node as TryStatement):

        WriteIndented
        Write 'try '
        WriteOpenBrace
        Visit node.ProtectedBlock

        assert 1 == len(node.ExceptionHandlers)

        hdl = node.ExceptionHandlers[0]
        WriteCloseBrace false
        Write " catch ($(hdl.Declaration.Name)) "
        WriteOpenBrace

        Visit hdl.Block

        if node.EnsureBlock:
            WriteCloseBrace false
            Write ' finally '
            WriteOpenBrace
            Visit node.EnsureBlock

        WriteCloseBrace

    def OnListLiteralExpression(node as ListLiteralExpression):
    """ The List type in Boo '[,,,]' is equivalent to the JS array
    """
        WriteDelimitedCommaSeparatedList('[', node.Items, ']')

    def OnArrayLiteralExpression(node as ArrayLiteralExpression):
    """ Arrays in Boo '(,,,)' are immutable but we convert them to plain JS arrays anyway
    """
        WriteDelimitedCommaSeparatedList('[', node.Items, ']')

    def OnHashLiteralExpression(node as HashLiteralExpression):
    """ Hashes are plain Javascript objects
    """
        is_short = len(node.Items) < 3
        if is_short:
            Write '{'
        else:
            WriteOpenBrace

        first = true
        for pair as ExpressionPair in node.Items:
            if not first:
                Write ', '
                if not is_short:
                    WriteLine
                    WriteIndented

            Visit pair.First
            Write ': '
            Visit pair.Second
            first = false

        if is_short:
            Write '}'
        else:
            WriteCloseBrace(node.ParentNode.NodeType != NodeType.MethodInvocationExpression)

    def WriteDelimitedCommaSeparatedList(opening, list as Expression*, closing):
        Write(opening)
        WriteCommaSeparatedList(list)
        Write(closing)

    def OnLabelStatement(node as LabelStatement):
        Map node
        WriteIndented "$(node.Name):"

    def OnGotoStatement(node as GotoStatement):
        WriteIndented
        Map node
        Write "continue $(node.Label.Name);"
        WriteLine

    def OnSelfLiteralExpression(node as SelfLiteralExpression):
        Map node
        Write 'this'

    def OnCharLiteralExpression(node as CharLiteralExpression):
    """ Chars in JS are strings of length 1 """
        Map node
        WriteStringLiteral(node.Value)

    def OnStringLiteralExpression(node as StringLiteralExpression):
        Map node
        WriteStringLiteral(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
    """
        re = node.Value

        start = re.IndexOf('/')
        stop = re.LastIndexOf('/')

        mod = re[stop:]
        re = re[start:stop]

        # Ignore white space
        re = /\s|\t/.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 mod.Contains('s'):
            re = /(?<!\\)\./.Replace(re, '[\\s\\S]')
            mod = mod.Replace('s', '')

        Map node
        Write "$re$mod"

    def OnIntegerLiteralExpression(node as IntegerLiteralExpression):
        Map node
        Write(node.Value.ToString())

    def OnDoubleLiteralExpression(node as DoubleLiteralExpression):
        Map node
        Write(node.Value.ToString("########0.0##########"))

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

        WriteIndented
        Visit node.Expression
        Visit node.Modifier
        Write ';'
        WriteLine

    def OnExpressionInterpolationExpression(node as ExpressionInterpolationExpression):
    """ We build either as string concatenation or as a literal array and then join it to form the string
            "foo \$bar" => 'foo' + bar
            "foo \$bar \$baz" -> ['foo', bar, ' ', baz].join('')
    """
        use_join = len(node.Expressions) > 3
        concat_str = (', ' if use_join else ' + ')

        Write '[' if use_join
        first = true
        for arg in node.Expressions:
            if arg.NodeType == NodeType.StringLiteralExpression:
                value = (arg as StringLiteralExpression).Value
                continue if not len(value)
                Write concat_str if not first
                WriteStringLiteral((arg as StringLiteralExpression).Value)
            else:
                # TODO: Use parens around expressions if needed
                Write concat_str if not first
                Visit(arg)

            first = false

        Write "].join('')" if use_join

    def OnMemberReferenceExpression(node as MemberReferenceExpression):
        # TODO: Check if the property name is a valid javascript ident and if not use ['xxx'] syntax

        # If the target is the `global` object skip it
        if node.Target.NodeType == NodeType.ReferenceExpression:
            target = node.Target as ReferenceExpression
            if target.Name == 'global':
                Write node.Name
                return
            # Check if it's a class. If so skip it by now
            # TODO: THIS DOESN'T WORK!!!
            elif false and target.ExpressionType and target.ExpressionType.BaseType.IsClass:
                Write node.Name
                return

        # Remove the $locals.$ prefix from closure variables
        if node.Target.ToString() == '$locals':
            Write node.Name[1:]
            return

        # Check if a node is bound to the main class
        def RefsMainClass(node as Node):
            if not node or not node.Entity:
                return false

            if not node.Entity isa TypeSystem.Internal.InternalClass:
                return false

            entity = node.Entity as TypeSystem.Internal.InternalClass
            if not entity.IsClass or not entity.TypeDefinition:
                return false

            defnode = entity.TypeDefinition as ClassDefinition
            if defnode.IsNested or not defnode.EnclosingModule:
                return false

            return true

        # Checks if a node is bound to a builtin type
        def RefsBuiltIn(node as Node):
            if not node or not node.Entity:
                return false

            return node.Entity.EntityType == TypeSystem.EntityType.BuiltinFunction

        if node.Target:
            print 'TARGET: ', node.Target
            print 'TARGET IsSynthetic', node.Target.IsSynthetic

            entity = node.Target.Entity
            if entity:
                print 'TARGET Entity', entity
                print 'TARGET Entity NodeType', entity.EntityType
                #if entity isa TypeSystem.ITypedEntity:
                #    typed = entity as TypeSystem.ITypedEntity
                #    print 'TARGET IsModule', typed.IsModule
                #    print 'TARGET IsClass', typed.IsClass
                #    print 'TARGET IsFinal', typed.IsFinal
                #    print 'TARGET TypeDefinition', typed.TypeDefinition  # Ast Node

        # Skip the target if it's the MainClass injected by Boo
        # TODO: Move to step
        if not RefsMainClass(node.Target):
            Visit node.Target
            Write '.'

        if RefsBuiltIn(node.Target):
            print 'BUILT IN', node.Target

        Map node
        Write node.Name

        # System
        # .IsSynthetic == false
        # .Entity isa TypeSystem.Core.ResolvedNamespaces, TypeSystem.Core.AbstractNamespace
        # .Entity.EntityType == Namespace

    def OnMethodInvocationExpression(node as MethodInvocationExpression):

        # TODO: We can use something like this to know which overloaded method we are calling
        /*
        print 'Target: ', node.Target.Entity
        entity as TypeSystem.IEntityWithParameters = node.Target.Entity
        if entity:
            # TODO: Check varargs ?
            i = 0
            for param as TypeSystem.IParameter in entity.GetParameters():
                print 'Arg: ', node.Arguments[i]
                print 'Param: ', param
                print 'Param.Type: ', param.Type
                i++
        */

        # HACK: Boo converts the equality comparison to a runtime call for those atoms
        #       without an static type on the complex ProcessMethodBodies step.
        #       Instead of changing that step we undo the transformation since it's
        #       much simpler although very dirty :(
        # TODO: Although we keep this hack it should be moved to its own dedicated step

        def UndoOperatorInvocation(node as MethodInvocationExpression, operator as BinaryOperatorType):
            expr = BinaryExpression(node.LexicalInfo)
            expr.Operator = operator
            expr.Left = node.Arguments[0]
            expr.Right = node.Arguments[1]
            Visit expr

        tref = node.Target.ToString()
        if tref == 'Boo.Lang.Runtime.RuntimeServices.EqualityOperator':
            UndoOperatorInvocation(node, BinaryOperatorType.Equality)
            return
        elif tref == 'Boo.Lang.Runtime.RuntimeServices.op_Match':
            UndoOperatorInvocation(node, BinaryOperatorType.Match)
            return
        elif tref == 'Boo.Lang.Runtime.RuntimeServices.op_NotMatch':
            UndoOperatorInvocation(node, BinaryOperatorType.NotMatch)
            return
        elif tref == 'Boo.Lang.Runtime.RuntimeServices.op_Member':
            UndoOperatorInvocation(node, BinaryOperatorType.Member)
            return
        elif tref == 'Boo.Lang.Runtime.RuntimeServices.op_NotMember':
            UndoOperatorInvocation(node, BinaryOperatorType.NotMember)
            return
        elif tref == 'Boo.Lang.Runtime.RuntimeServices.GetEnumerable':
            Visit node.Arguments[0]
            return
        elif tref =~ 'Boo.Lang.Runtime.RuntimeServices':
            raise "Found a RuntimeServices invocation: $tref"
        elif tref =~ /^BooJs\.Lang\.BuiltinsModule\./:
            # TODO: This is a HACK!!!
            Write 'Boo.' + tref.Substring(len('BooJs.Lang.BuiltinsModule.')) + '('
            WriteCommaSeparatedList node.Arguments
            Write ')'
            return

        # Revert: CompilerGenerated.__FooModule_foo$callable0$7_9__(xxx, __addressof__(FooModule.$foo$closure$1))
        if len(node.Arguments) == 2:
            arg = node.Arguments[1]
            if arg.NodeType == NodeType.MethodInvocationExpression:
                method as MethodInvocationExpression = arg
                if '__addressof__' == method.Target.ToString():
                    arg = method.Arguments[0]
                    Write "/*CLOSURE: $arg*/"

        # Convert: closure.Invoke() -> closure()
        if node.Target isa MemberReferenceExpression:
            target = node.Target as MemberReferenceExpression
            if target.Name == 'Invoke' and target.ExpressionType isa Boo.Lang.Compiler.TypeSystem.Core.AnonymousCallableType:
                node.Target = target.Target

            # HACK: Dirty way to convert back hash access to use index based syntax instead of method calls
            # TODO: Move this to a compiler step
            elif target.Name == 'get_Item':
                Visit target.Target
                Write '['
                Visit node.Arguments[0]
                Write ']'
                return
            elif target.Name == 'set_Item':
                Visit target.Target
                Write '['
                Visit node.Arguments[0]
                Write '] = '
                Visit node.Arguments[1]
                return

        # "Eval" calls take the form:
        #
        #    @( stmt1, stmt2, ...., return_stmt )
        #
        # so we can convert them to a self invoking anonymous function that returns the last
        # argument.
        #
        # Note: New variables are declared in the enclosing scope not wrapped in the anonymous
        #       function.
        #
        if '@' == node.Target.ToString():
            Write '(function(){ '
            # Execute statements passed as arguments
            l = len(node.Arguments)
            for i in range(l):
                # Return the result of the last statement
                if i == l-1:
                    Write 'return '
                Visit node.Arguments[i]
                Write '; '
            Write '})()'
            return

        Visit node.Target
        Write '('
        WriteCommaSeparatedList node.Arguments

        # TODO: What to do with named arguments?
        # Although Boo doesn't support the definition of named params it does support
        # their use when calling methods. If the method is a constructor then it automatically
        # sets those properties:
        #  Foo(x:1, y:10)   ->  function Foo(){ this.x = 1; this.y = 10

        #if len(node.NamedArguments):
        #    if len(node.Arguments):
        #        Write ', '
        #    WriteCommaSeparatedList node.NamedArguments

        Write ')'

    def OnReturnStatement(node as ReturnStatement):
        WriteIndented 'return '
        Visit node.Expression
        WriteLine ';'

    def OnRaiseStatement(node as RaiseStatement):
        WriteIndented 'throw '
        if node.Exception isa MethodInvocationExpression:
            Write 'new '
        Visit node.Exception
        WriteLine

    def OnWhileStatement(node as WhileStatement):
        WriteIndented 'while ('
        Visit node.Condition
        Write ') '
        WriteOpenBrace
        Visit node.Block
        WriteCloseBrace

    def OnUnlessStatement(node as UnlessStatement):
        WriteIndented 'if (! '
        WriteWithOptionalParens node.Condition
        Write ') '
        WriteOpenBrace
        Visit(node.Block)
        WriteCloseBrace

    def OnBreakStatement(node as BreakStatement):
        WriteIndented
        Map node
        WriteLine 'break;'

    def OnContinueStatement(node as ContinueStatement):
        WriteIndented
        Map node
        WriteLine 'continue;'

    def OnUnaryExpression(node as UnaryExpression):
        # Make sure negation applies correctly to its operand
        if node.Operator == UnaryOperatorType.LogicalNot:
            Write '!('
            Visit node.Operand
            Write ')'
            return

        Write '(' if NeedsParensAround(node)

        isPostOp = AstUtil.IsPostUnaryOperator(node.Operator)
        Write GetUnaryOperatorText(node.Operator) if not isPostOp
        parens = NeedsParensAround(node.Operand)
        Write '(' if parens
        Visit node.Operand
        Write ')' if parens
        Write GetUnaryOperatorText(node.Operator) if isPostOp

        Write ')' if NeedsParensAround(node)

    def GetUnaryOperatorText(op as UnaryOperatorType):
        # TODO: In ProcessMethod.ExpandSimpleIncrementDecrement this is expanded
        if op == UnaryOperatorType.PostIncrement or op == UnaryOperatorType.Increment:
            return '++'
        # TODO: In ProcessMethod.ExpandSimpleIncrementDecrement this is expanded
        elif op == UnaryOperatorType.PostDecrement or op == UnaryOperatorType.Decrement:
            return '--'
        elif op == UnaryOperatorType.UnaryNegation:
            return '-'
        elif op == UnaryOperatorType.LogicalNot:
            return '!'
        elif op == UnaryOperatorType.OnesComplement:
            return '~'
        elif op == UnaryOperatorType.Explode:
            raise 'Explode operator "*" is not supported'
        elif op == UnaryOperatorType.AddressOf:
            raise 'AddressOf operator "&" is not supported'
        elif op == UnaryOperatorType.Indirection:
            raise 'Indirection operator "*" is not supported'
        else:
            raise 'Invalid operator "' + op + '"'

    def BinaryAssign(node as BinaryExpression):
        # Wrap in parens if it's an assigment inside an expression
        parens = not node.ParentNode isa Statement
        Write '(' if parens

        Visit node.Left
        Write ' = '
        Visit node.Right

        Write ')' if parens

    def BinaryExponentiation(node as BinaryExpression):
        Write 'Math.pow('
        Visit node.Left
        Write ', '
        Visit node.Right
        Write ')'

    def BinaryMatch(node as BinaryExpression):
        type = TypeSystem.TypeSystemServices.GetExpressionType(node.Right)
        if type.ToString() == 'BooJs.Lang.RegExp':
            Visit node.Right
            Write '.test('
            Visit node.Left
            Write ')'
            return

        # handle strings
        Write '(-1 !== '
        Visit node.Left
        Write '.indexOf('
        Visit node.Right
        Write '))'

    def OnBinaryExpression(node as BinaryExpression):

        if node.Operator == BinaryOperatorType.Assign:
            BinaryAssign(node)
        elif node.Operator == BinaryOperatorType.Exponentiation:
            BinaryExponentiation(node)
        elif node.Operator == BinaryOperatorType.Match: # a =~ b
            BinaryMatch(node)
        elif node.Operator == BinaryOperatorType.NotMatch: # a !~ b
            # TODO: If we have a runtime we can match regexp too
            Write '(-1 === '
            Visit node.Left
            Write '.indexOf('
            Visit node.Right
            Write '))'
        elif node.Operator == BinaryOperatorType.NotMember: # a not in b -> !(a in b)
            Write '!('
            Visit node.Left
            Write ' in '
            Visit node.Right
            Write ')'
        elif node.Operator == BinaryOperatorType.TypeTest: # a isa type -> typeof a === 'type'  OR  a instanceof type
            # isa rhs is encoded in a typeof expression
            if node.Right isa TypeofExpression \
            and (node.Right as TypeofExpression).Type isa SimpleTypeReference:
                # TODO: We need to convert type names to JS ones somewhere
                # TODO: Shall we also check for instanceof Number, String, Array... ???
                type = (node.Right as TypeofExpression).Type as SimpleTypeReference

                if type.Name.IndexOf('Error') >= 0:
                    Visit node.Left
                    Write ' instanceof '
                    Visit node.Right
                else:
                    Write 'typeof '
                    Visit node.Left
                    Write " === "
                    if type.Name == 'bool':
                        Write "'boolean'"
                    elif type.Name == 'int' or type.Name == 'uint' or type.Name == 'double':
                        Write "'number'"
                    elif type.Name == 'void':
                        Write "'undefined'"
                    elif type.Name == 'callable':
                        Write "'function'"
                    else:
                        Write "'$(type.Name)'"

            else:
                Visit node.Left
                Write ' instanceof '
                Visit node.Right

        else:
            parens = NeedsParensAround(node)
            Write '(' if parens
            Visit node.Left
            Write " "
            Write GetBinaryOperatorText(node.Operator)
            Write " "
            Visit node.Right
            Write ')' if parens

    def OnSimpleTypeReference(node as SimpleTypeReference):
        # TODO: Why is this happending?
        if node.ToString() == 'System.Object' or node.ToString() == 'object':
            print 'WARNING: SimpleTypeReference = ', node
            return

        if node.Name.IndexOf('BooJs.Lang.') == 0:
            Write node.Name.Substring('BooJs.Lang.'.Length)
        else:
            Write node.Name

    def GetBinaryOperatorText(op as BinaryOperatorType):

        return '=' if op == BinaryOperatorType.Assign
        # Note: We use equality in value and type in JS
        return '==' if op == BinaryOperatorType.Equality
        return '!=' if op == BinaryOperatorType.Inequality
        return '+' if op == BinaryOperatorType.Addition
        return '-' if op == BinaryOperatorType.Subtraction
        return '*' if op == BinaryOperatorType.Multiply
        return '/' if op == BinaryOperatorType.Division
        return '%' if op == BinaryOperatorType.Modulus
        return '+=' if op == BinaryOperatorType.InPlaceAddition
        return '-=' if op == BinaryOperatorType.InPlaceSubtraction
        return '*=' if op == BinaryOperatorType.InPlaceMultiply
        return '%=' if op == BinaryOperatorType.InPlaceModulus
        return '/=' if op == BinaryOperatorType.InPlaceDivision
        return '&=' if op == BinaryOperatorType.InPlaceBitwiseAnd
        return '|=' if op == BinaryOperatorType.InPlaceBitwiseOr
        return '^=' if op == BinaryOperatorType.InPlaceExclusiveOr
        return '>' if op == BinaryOperatorType.GreaterThan
        return '>=' if op == BinaryOperatorType.GreaterThanOrEqual
        return '<' if op == BinaryOperatorType.LessThan
        return '<=' if op == BinaryOperatorType.LessThanOrEqual

        # TODO: Does it work most of the time???
        return 'in' if op == BinaryOperatorType.Member

        return '===' if op == BinaryOperatorType.ReferenceEquality
        return '!==' if op == BinaryOperatorType.ReferenceInequality

        return 'instanceof' if op == BinaryOperatorType.TypeTest
        return '||' if op == BinaryOperatorType.Or
        return '&&' if op == BinaryOperatorType.And

        return '|' if op == BinaryOperatorType.BitwiseOr
        return '&' if op == BinaryOperatorType.BitwiseAnd
        return '^' if op == BinaryOperatorType.ExclusiveOr
        return '<<' if op == BinaryOperatorType.ShiftLeft
        return '>>' if op == BinaryOperatorType.ShiftRight
        return '<<=' if op == BinaryOperatorType.InPlaceShiftLeft
        return '>>=' if op == BinaryOperatorType.InPlaceShiftRight

        raise 'Operator $(op) is not implemented'

    def NeedsParensAround(node as Expression):
        t = node.NodeType
        return false if t == NodeType.StringLiteralExpression
        return false if t == NodeType.CharLiteralExpression
        return false if t == NodeType.BoolLiteralExpression
        return false if t == NodeType.IntegerLiteralExpression
        return false if t == NodeType.DoubleLiteralExpression
        return false if t == NodeType.NullLiteralExpression
        return false if t == NodeType.ReferenceExpression
        return false if t == NodeType.ListLiteralExpression
        return false if t == NodeType.ArrayLiteralExpression
        return false if t == NodeType.MethodInvocationExpression
        return false if t == NodeType.UnaryExpression

        # TODO: Not very sure about this
        if node.ParentNode:
            t = node.ParentNode.NodeType
            return false if t == NodeType.ExpressionStatement
            #return false if t == NodeType.IfStatement
            #return false if t == NodeType.WhileStatement
            #return false if t == NodeType.UnlessStatement

        return true

    def WriteCallableDefinitionHeader(keyword as string, node as CallableDefinition):
        # TODO: Inspect params and return to generate type annotations for Closure
        WriteIndented keyword
        Map node
        Write node.Name
        WriteParameterList(node.Parameters, '(', ')')

    def WriteParameterList(params as ParameterDeclarationCollection, st, ed):
        Write(st)
        i = 0
        for param in params:
            if i > 0:
                Write(', ')
            Visit(param)
            i++
        Write(ed)

    def OnParameterDeclaration(p as ParameterDeclaration):
        if p.IsParamArray: Write("*")
        Map(p)
        Write(p.Name);

    def OnEnumDefinition(node as EnumDefinition):
        # TODO: Prefix with namespace
        Write 'var '

        Map node
        Write "$(node.FullName) = "
        WriteOpenBrace
        first = true
        for member as EnumMember in node.Members:
            assert member.Initializer != null, 'Enum definition without an initializer value!'
            WriteLine ',' if not first
            WriteIndented
            Map member
            Write member.Name
            Write ': '
            Visit member.Initializer
            first = false

        WriteLine
        WriteCloseBrace

    def ___OnClassDefinition(node as ClassDefinition):
        Write "$(node.Name) = function()"
        WriteOpenBrace

        if len(node.BaseTypes):
            Write '/* extends '
            WriteCommaSeparatedList(node.BaseTypes)
            Write '*/'
            WriteLine

        statics = []
        methods = []
        for member as TypeMember in node.Members:
            # Static members are defined outside the constructor
            if member.IsStatic:
                statics.Push(member)
                continue

            # Call the constructor method
            if member isa Constructor:
                WriteIndented 'this.constructor.apply(this, arguments);'
                WriteLine

            # Collect to define the prototype
            if member isa Method:
                methods.Push(member)
                continue

            WriteIndented
            Visit(member)
            WriteLine()

        WriteCloseBrace

        # Setup the static fields
        for member as TypeMember in statics:
            # Inline the static constructor
            if member isa Constructor:
                Visit((member as Constructor).Body)
                continue

            WriteIndented "$(member.FullName) = "
            Visit(member)
            WriteLine

        # Setup prototype
        for member as TypeMember in methods:
            WriteIndented member.DeclaringType.FullName
            Write ".prototype.$(member.Name) = "
            Visit(member)
            WriteLine

    def OnField(f as Field):
        # Not supported
        return

    def OnConstructor(node as Constructor):
        # Not supported
        return

    def WriteTypeDefinition(keyword, node as TypeDefinition):
        raise 'This is not yet implemented'

        #WriteAttributes(node.Attributes, true)
        #WriteModifiers(node)
        WriteIndented
        Write keyword
        Write ' '

        splice = node.ParentNode as SpliceTypeMember
        if splice:
            #WriteSplicedExpression(splice.NameExpression)
            pass
        else:
            Write(node.Name)

        #if len(node.GenericParameters):
        #    WriteGenericParameterList(node.GenericParameters);

        if len(node.BaseTypes):
            Write("(")
            WriteCommaSeparatedList(node.BaseTypes)
            Write(")")

        WriteLine(":")
        if len(node.Members):
            for member as TypeMember in node.Members:
                print member.NodeType
                Visit(member)
                WriteLine()
        else:
            Write 'pass'

    def OnExpressionPair(pair as ExpressionPair):
        Visit pair.First
        Write ': '
        Visit pair.Second

    def WriteStringLiteral(text as string):
        WriteStringLiteral text, "'"

    def WriteStringLiteral(text as string, quote as string):
        Write quote
        WriteStringContent text, quote
        Write quote

    def WriteStringContent(text as string, quote as string):
        for ch in text:
            str = ch.ToString()  # Convet to string from char
            if str == '\r':
                Write '\\r'
            elif str == '\n':
                Write '\\n'
            elif str == '\t':
                Write '\\t'
            elif str == '\0':
                Write '\\0'
            elif str == '\\':
                Write '\\\\'
            elif str == "'" and str == quote:
                Write "\\'"
            elif str == '"' and str == quote:
                Write '\\"'
            else:
                Write(str)

class PrintBooJs(PrintBoo):

    override def Run():
        visitor = BooJsPrinterVisitor(OutputWriter)
        visitor.Initialize(Context)
        visitor.Print(CompileUnit);

namespace BooJs.Compiler.Steps

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

import BooJs.Compiler.SourceMap

class BooJsPrinterVisitor(Visitors.TextEmitter):

    _context as CompilerContext

    srcmap as MapBuilder

    def constructor(writer as System.IO.TextWriter):
        super(writer)
        IndentText = '  '

        srcmap = MapBuilder()

    def Initialize(context as CompilerContext):
        _context = context

    def Print(ast as CompileUnit):
        OnCompileUnit(ast)

        WriteLine '//@ sourceMappingURL=map.js.map'
        print 'var map = ' + srcmap.ToString()

    def WriteLine():
        srcmap.NewLine()
        super.WriteLine()

    def Write(str as string):
        srcmap.Column += str.Length
        super.Write(str)

    def Map(node as Node):
    """ Maps the given node lexical info to the current position in the generated file
    """
        srcmap.Segment(node)

    def OnBoolLiteralExpression(node as BoolLiteralExpression):
        Write( ('true' if node.Value else 'false') )

    def OnNullLiteralExpression(node as NullLiteralExpression):
        Write 'null'

    def OnModule(node as Module):

        # HACK: ProcessMethodBodies step is too complex so we opt for reversing some
        #       of the stuff it does instead of modifying it. Here we just ignore
        #       any modules it generates to support 'dynamic' features at runtime
        if node.Name == 'CompilerGenerated':
            WriteLine
            Write '/*** CompilerGenerated ***********************'
            WriteLine

        Visit(node.Namespace)

        if node.Imports.Count > 0:
            Visit(node.Imports)
            WriteLine()

        for member in node.Members:
            Visit(member)
            WriteLine()

        if node.Globals:
            Visit(node.Globals.Statements)

        if node.Name == 'CompilerGenerated':
            WriteLine '*** /CompilerGenerated **********************/'

    def WriteLocals(locals as LocalCollection):
    """ Write locals ensuring they are not repeated """
        found = []
        for local in locals:
            continue if local.Name == '$locals'
            continue if local.Name in found
            found.Push(local.Name)
            Visit local

    def OnMethod(m as Method):

        # Types are already resolved so we can just check if it was flagged as a generator
        entity as TypeSystem.Internal.InternalMethod = m.Entity
        if entity.IsGenerator:
            print 'Generator'

        if m.IsRuntime:
            WriteIndented('// runtime')
            WriteLine()

        if /^\$\w+\$closure\$\d+/.IsMatch(m.Name):
            print 'Skipping closure method', m.Name
            return

        # HACK!!! Find assignments of $locals.$<name> to define these as local variables
        # TODO: Improve the algorithm to support all cases
        # TODO: Move to a separate step
        def FindClosureLocals(block as Block):
            for st in block.Statements:
                if st isa Block:
                    FindClosureLocals(st)
                elif st isa Method:
                    FindClosureLocals((st as Method).Body)
                elif st isa BlockExpression:
                    FindClosureLocals((st as BlockExpression).Body)
                elif st isa ExpressionStatement:
                    es = st as ExpressionStatement
                    if es.Expression isa BinaryExpression:
                        be = es.Expression as BinaryExpression
                        if /^\$locals\.\$/.IsMatch(be.Left.ToString()):
                            str = be.Left.ToString()
                            parts = str.Split(char('.'))
                            local = Local()
                            local.Name = parts[1][1:]
                            m.Locals.Add(local)

        FindClosureLocals(m.Body)

        # HACK: If we detect the Main method we just output its statements
        if m.Name == 'Main':
            WriteLocals(m.Locals)
            Visit m.Body
            return

        WriteCallableDefinitionHeader('function ', m)
        WriteOpenBrace
        WriteLocals(m.Locals)
        Visit m.Body
        WriteCloseBrace

    def OnSlicingExpression(node as SlicingExpression):
        if len(node.Indices) != 1:
            raise 'Only one index is supported when slicing'

        Visit node.Target
        Write '['
        Visit node.Indices[0]
        Write ']'

    def OnUnpackStatement(node as UnpackStatement):
        WriteLine 'var __unpack;'

        Write '__unpack = '
        Visit node.Expression

        idx = 0
        for decl in node.Declarations:
            Write ", $(decl.Name) = __unpack[$idx]"
            idx++

        WriteLine ';'

    def OnBlockExpression(node as BlockExpression):
    """ Javascript has native support for closures thus the conversion is very simple.
    """
        Write 'function('
        if len(node.Parameters):
            WriteCommaSeparatedList(node.Parameters)
        Write ')'
        if node.Body.IsEmpty:
            Write '{}'
        elif len(node.Body.Statements) == 1 \
        and  len(node.Body.Statements[0].ToString()) < 30:
            # TODO: When it's just one statement we should inject a return if not present
            #       Seems like Boo already does that :)
            Write '{ '
            # TODO: Avoid generating a new line
            Visit node.Body.Statements[0]
            Write ' }'
        else:
            WriteOpenBrace
            Visit(node.Body.Statements)
            WriteCloseBrace false

    def WriteOpenBrace():
        Write '{'
        WriteLine
        Indent
        WriteIndented

    def WriteCloseBrace(cr as bool):
        Dedent
        WriteIndented
        Write '}'
        WriteLine if cr
        WriteLine if cr

    def WriteCloseBrace():
        WriteCloseBrace(true)

    def WriteAnnotation(str as string):
        lines = str.Split("\n"[0])
        if len(lines) == 1:
            Write '/** ' + str + ' */'
        else:
            WriteLine '/**'
            for ln in lines:
                WriteIndented ' * '
                Write ln
                WriteLine
            WriteIndented ' */'

    def OnLocal(node as Local):
        # HACK: We should find a better way to compare the type. If it matches
        #       the special global type (ie: jQuery as global) then we avoid defining
        #       it, which would shadow the global variable
        #ilocal = node.Entity as Boo.Lang.Compiler.TypeSystem.ITypedEntity
        #if ilocal.Type.ToString() == 'Boojs.Lang.global':
        #    return

        entity = node.Entity as TypeSystem.ITypedEntity

        # TODO: Add proper type annotations
        WriteIndented
        WriteAnnotation "@type {$(entity.Type)}"
        Write " var $(node.Name);"
        WriteLine

    def OnReferenceExpression(node as ReferenceExpression):
        # TODO: Check name for invalid chars?
        Map node
        Write node.Name

    def OnDeclarationStatement(node as DeclarationStatement):
        WriteIndented 'var '
        Map node
        Write node.Declaration.Name
        if node.Initializer:
            Write ' = '
            Visit node.Initializer
        WriteLine ';'

    def OnIfStatement(node as IfStatement):

        last_had_braces = false

        def IsElIf(block as Block):
            return false if not block
            return false if block.Statements.Count != 1
            return block.Statements[0] isa IfStatement

        def WriteCondBlock(keyword, node as IfStatement):
            Write keyword + ' ('
            Visit node.Condition
            Write ') '
            if len(node.TrueBlock.Statements):
                WriteOpenBrace
                last_had_braces = true
                Visit(node.TrueBlock.Statements)
            else:
                WritePass

        WriteIndented
        WriteCondBlock('if', node)

        block = node.FalseBlock
        while IsElIf(block):
            stmt as IfStatement = block.Statements[0]
            if last_had_braces:
                WriteCloseBrace false
                WriteCondBlock(' else if', stmt)
            else:
                WriteCondBlock('else if', stmt)
            block = stmt.FalseBlock

        if block:
            if last_had_braces:
                last_had_braces = false
                WriteCloseBrace false
                WriteIndented ' else '
            else:
                WriteIndented 'else '

            if len(block.Statements) > 1:
                WriteOpenBrace
                last_had_braces = true
                Visit block.Statements
            elif len(block.Statements) == 1:
                Visit block.Statements
            else:
                Write '{}'
                WriteLine

        WriteCloseBrace if last_had_braces

    def WritePass():
        WriteLine '"pass";'

    def OnConditionalExpression(node as ConditionalExpression):
    """ Convert to the ternary operator.
            (10 if true else 20)  -->  true ? 10 : 20
    """
        WriteWithOptionalParens node.Condition
        Write ' ? '
        WriteWithOptionalParens node.TrueValue
        Write ' : '
        WriteWithOptionalParens node.FalseValue

    def WriteWithOptionalParens(node as Node):
        parens = NeedsParensAround(node)
        if parens:
            WriteWithParens(node)
        else:
            Visit node

    def WriteWithParens(node as Node):
        Write '('
        Visit node
        Write ')'

    def OnTryStatement(node as TryStatement):

        WriteIndented
        Write 'try '
        WriteOpenBrace
        Visit node.ProtectedBlock

        assert 1 == len(node.ExceptionHandlers)

        hdl = node.ExceptionHandlers[0]
        WriteCloseBrace false
        Write " catch ($(hdl.Declaration.Name)) "
        WriteOpenBrace

        Visit hdl.Block

        if node.EnsureBlock:
            WriteCloseBrace false
            Write ' finally '
            WriteOpenBrace
            Visit node.EnsureBlock

        WriteCloseBrace

    def OnListLiteralExpression(node as ListLiteralExpression):
    """ The List type in Boo '[,,,]' is equivalent to the JS array
    """
        WriteDelimitedCommaSeparatedList('[', node.Items, ']')

    def OnArrayLiteralExpression(node as ArrayLiteralExpression):
    """ Arrays in Boo '(,,,)' are immutable but we convert them to plain JS arrays anyway
    """
        WriteDelimitedCommaSeparatedList('[', node.Items, ']')

    def OnHashLiteralExpression(node as HashLiteralExpression):
    """ Hashes are plain Javascript objects
    """
        is_short = len(node.Items) < 3
        if is_short:
            Write '{'
        else:
            WriteOpenBrace

        first = true
        for pair as ExpressionPair in node.Items:
            if not first:
                Write ', '
                if not is_short:
                    WriteLine
                    WriteIndented

            Visit pair.First
            Write ': '
            Visit pair.Second
            first = false

        if is_short:
            Write '}'
        else:
            WriteCloseBrace(node.ParentNode.NodeType != NodeType.MethodInvocationExpression)

    def WriteDelimitedCommaSeparatedList(opening, list as Expression*, closing):
        Write(opening)
        WriteCommaSeparatedList(list)
        Write(closing)

    def OnLabelStatement(node as LabelStatement):
        Map node
        WriteIndented "$(node.Name):"

    def OnGotoStatement(node as GotoStatement):
        WriteIndented
        Map node
        Write "continue $(node.Label.Name);"
        WriteLine

    def OnSelfLiteralExpression(node as SelfLiteralExpression):
        Map node
        Write 'this'

    def OnCharLiteralExpression(node as CharLiteralExpression):
    """ Chars in JS are strings of length 1 """
        Map node
        WriteStringLiteral(node.Value)

    def OnStringLiteralExpression(node as StringLiteralExpression):
        Map node
        WriteStringLiteral(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
    """
        re = node.Value
        mod = re[-1:]
        if mod == '/':
            re = re[1:-1]
            mod = ''
        else:
            re = re[1:-2]

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

        Map node
        Write "/$re/$mod"

    def OnIntegerLiteralExpression(node as IntegerLiteralExpression):
        Map node
        Write(node.Value.ToString())

    def OnDoubleLiteralExpression(node as DoubleLiteralExpression):
        Map node
        Write(node.Value.ToString("########0.0##########"))

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

        WriteIndented
        Visit node.Expression
        Visit node.Modifier
        Write ';'
        WriteLine

    def OnExpressionInterpolationExpression(node as ExpressionInterpolationExpression):
    """ We build either as string concatenation or as a literal array and then join it to form the string
            "foo \$bar" => 'foo' + bar
            "foo \$bar \$baz" -> ['foo', bar, ' ', baz].join('')
    """
        use_join = len(node.Expressions) > 3
        concat_str = (', ' if use_join else ' + ')

        Write '[' if use_join
        first = true
        for arg in node.Expressions:
            if arg.NodeType == NodeType.StringLiteralExpression:
                value = (arg as StringLiteralExpression).Value
                continue if not len(value)
                Write concat_str if not first
                WriteStringLiteral((arg as StringLiteralExpression).Value)
            else:
                # TODO: Use parens around expressions if needed
                Write concat_str if not first
                Visit(arg)

            first = false

        Write "].join('')" if use_join

    def OnMemberReferenceExpression(node as MemberReferenceExpression):
        # TODO: Check if the property name is a valid javascript ident and if not use ['xxx'] syntax

        # If the target is the `global` object skip it
        if node.Target.NodeType == NodeType.ReferenceExpression:
            target = node.Target as ReferenceExpression
            if target.Name == 'global':
                Write node.Name
                return
            # Check if it's a class. If so skip it by now
            # TODO: THIS DOESN'T WORK!!!
            elif false and target.ExpressionType and target.ExpressionType.BaseType.IsClass:
                Write node.Name
                return

        # Remove the $locals.$ prefix for closure variables
        if node.Target.ToString() == '$locals':
            Write node.Name[1:]
            return

        # Check if a node is bound to the main class
        def RefsMainClass(node as Node):
            if not node or not node.Entity:
                return false

            if not node.Entity isa TypeSystem.Internal.InternalClass:
                return false

            entity = node.Entity as TypeSystem.Internal.InternalClass
            if not entity.IsClass or not entity.TypeDefinition:
                return false

            defnode = entity.TypeDefinition as ClassDefinition
            if defnode.IsNested or not defnode.EnclosingModule:
                return false

            return true

        # Checks if a node is bound to a builtin type
        def RefsBuiltIn(node as Node):
            if not node or not node.Entity:
                return false

            return node.Entity.EntityType == TypeSystem.EntityType.BuiltinFunction

        if node.Target:
            print 'TARGET: ', node.Target
            print 'TARGET IsSynthetic', node.Target.IsSynthetic

            entity = node.Target.Entity
            if entity:
                print 'TARGET Entity', entity
                print 'TARGET Entity NodeType', entity.EntityType
                #if entity isa TypeSystem.ITypedEntity:
                #    typed = entity as TypeSystem.ITypedEntity
                #    print 'TARGET IsModule', typed.IsModule
                #    print 'TARGET IsClass', typed.IsClass
                #    print 'TARGET IsFinal', typed.IsFinal
                #    print 'TARGET TypeDefinition', typed.TypeDefinition  # Ast Node

        # Skip the target if it's the MainClass injected by Boo
        # TODO: Move to step
        if not RefsMainClass(node.Target):
            Visit node.Target
            Write '.'

        if RefsBuiltIn(node.Target):
            print 'BUILT IN', node.Target

        Map node
        Write node.Name

        # System
        # .IsSynthetic == false
        # .Entity isa TypeSystem.Core.ResolvedNamespaces, TypeSystem.Core.AbstractNamespace
        # .Entity.EntityType == Namespace

    def OnMethodInvocationExpression(node as MethodInvocationExpression):

        # TODO: We can use something like this to know which overloaded method we are calling
        /*
        print 'Target: ', node.Target.Entity
        entity as TypeSystem.IEntityWithParameters = node.Target.Entity
        if entity:
            # TODO: Check varargs ?
            i = 0
            for param as TypeSystem.IParameter in entity.GetParameters():
                print 'Arg: ', node.Arguments[i]
                print 'Param: ', param
                print 'Param.Type: ', param.Type
                i++
        */

        # HACK: Boo converts the equality comparison to a runtime call for those atoms
        #       without an static type on the complex ProcessMethodBodies step.
        #       Instead of changing that step we undo the transformation since it's
        #       much simple although very dirty :(
        # TODO: Although we keep this hack it should be moved to its own dedicated step

        def UndoOperatorInvocation(node as MethodInvocationExpression, operator as BinaryOperatorType):
            expr = BinaryExpression(node.LexicalInfo)
            expr.Operator = operator
            expr.Left = node.Arguments[0]
            expr.Right = node.Arguments[1]
            Visit expr

        tref = node.Target.ToString()
        if tref == 'Boo.Lang.Runtime.RuntimeServices.EqualityOperator':
            UndoOperatorInvocation(node, BinaryOperatorType.Equality)
            return
        elif tref == 'Boo.Lang.Runtime.RuntimeServices.op_Match':
            UndoOperatorInvocation(node, BinaryOperatorType.Match)
            return
        elif tref == 'Boo.Lang.Runtime.RuntimeServices.op_NotMatch':
            UndoOperatorInvocation(node, BinaryOperatorType.NotMatch)
            return
        elif tref == 'Boo.Lang.Runtime.RuntimeServices.op_Member':
            UndoOperatorInvocation(node, BinaryOperatorType.Member)
            return
        elif tref == 'Boo.Lang.Runtime.RuntimeServices.op_NotMember':
            UndoOperatorInvocation(node, BinaryOperatorType.NotMember)
            return
        elif tref == 'Boo.Lang.Runtime.RuntimeServices.GetEnumerable':
            Visit node.Arguments[0]
            return
        elif tref =~ 'Boo.Lang.Runtime.RuntimeServices':
            raise "Found a RuntimeServices invocation: $tref"
        elif tref =~ /^BooJs\.Lang\.BuiltinsModule\./:
            # TODO: This is a HACK!!!
            Write 'Boo.' + tref.Substring(len('BooJs.Lang.BuiltinsModule.')) + '('
            WriteCommaSeparatedList node.Arguments
            Write ')'
            return

        # Revert: CompilerGenerated.__FooModule_foo$callable0$7_9__(xxx, __addressof__(FooModule.$foo$closure$1))
        if len(node.Arguments) == 2:
            arg = node.Arguments[1]
            if arg.NodeType == NodeType.MethodInvocationExpression:
                method as MethodInvocationExpression = arg
                if '__addressof__' == method.Target.ToString():
                    arg = method.Arguments[0]
                    Write "/*CLOSURE: $arg*/"

        # Convert: closure.Invoke() -> closure()
        if node.Target isa MemberReferenceExpression:
            target = node.Target as MemberReferenceExpression
            if target.Name == 'Invoke' and target.ExpressionType isa Boo.Lang.Compiler.TypeSystem.Core.AnonymousCallableType:
                node.Target = target.Target

        Visit node.Target
        Write '('
        WriteCommaSeparatedList node.Arguments

        # TODO: What to do with named arguments?
        # Although Boo doesn't support the definition of named params it does support
        # their use when calling methods. If the method is a constructor then it automatically
        # sets those properties:
        #  Foo(x:1, y:10)   ->  function Foo(){ this.x = 1; this.y = 10

        #if len(node.NamedArguments):
        #    if len(node.Arguments):
        #        Write ', '
        #    WriteCommaSeparatedList node.NamedArguments

        Write ')'

    def OnReturnStatement(node as ReturnStatement):
        WriteIndented 'return '
        Visit node.Expression
        WriteLine ';'

    def OnRaiseStatement(node as RaiseStatement):
        WriteIndented 'throw '
        if node.Exception isa MethodInvocationExpression:
            Write 'new '
        Visit node.Exception
        WriteLine

    def OnWhileStatement(node as WhileStatement):
        WriteIndented 'while ('
        Visit node.Condition
        Write ') '
        WriteOpenBrace
        Visit node.Block
        WriteCloseBrace

    def OnUnlessStatement(node as UnlessStatement):
        WriteIndented 'if (! '
        WriteWithOptionalParens node.Condition
        Write ') '
        WriteOpenBrace
        Visit(node.Block)
        WriteCloseBrace

    def OnBreakStatement(node as BreakStatement):
        WriteIndented
        Map node
        WriteLine 'break;'

    def OnContinueStatement(node as ContinueStatement):
        WriteIndented
        Map node
        WriteLine 'continue;'

    def OnUnaryExpression(node as UnaryExpression):
        # Make sure negation applies correctly to its operand
        if node.Operator == UnaryOperatorType.LogicalNot:
            Write '!('
            Visit node.Operand
            Write ')'
            return

        Write '(' if NeedsParensAround(node)

        isPostOp = AstUtil.IsPostUnaryOperator(node.Operator)
        Write GetUnaryOperatorText(node.Operator) if not isPostOp
        parens = NeedsParensAround(node.Operand)
        Write '(' if parens
        Visit node.Operand
        Write ')' if parens
        Write GetUnaryOperatorText(node.Operator) if isPostOp

        Write ')' if NeedsParensAround(node)

    def GetUnaryOperatorText(op as UnaryOperatorType):
        # TODO: In ProcessMethod.ExpandSimpleIncrementDecrement this is expanded
        if op == UnaryOperatorType.PostIncrement or op == UnaryOperatorType.Increment:
            return '++'
        # TODO: In ProcessMethod.ExpandSimpleIncrementDecrement this is expanded
        elif op == UnaryOperatorType.PostDecrement or op == UnaryOperatorType.Decrement:
            return '--'
        elif op == UnaryOperatorType.UnaryNegation:
            return '-'
        elif op == UnaryOperatorType.LogicalNot:
            return '!'
        elif op == UnaryOperatorType.OnesComplement:
            return '~'
        elif op == UnaryOperatorType.Explode:
            raise 'Explode operator "*" is not supported'
        elif op == UnaryOperatorType.AddressOf:
            raise 'AddressOf operator "&" is not supported'
        elif op == UnaryOperatorType.Indirection:
            raise 'Indirection operator "*" is not supported'
        else:
            raise 'Invalid operator "' + op + '"'

    def BinaryAssign(node as BinaryExpression):
        # Wrap in parens if it's an assigment inside an expression
        parens = not node.ParentNode isa Statement
        Write '(' if parens

        Visit node.Left
        Write ' = '
        Visit node.Right

        Write ')' if parens

    def BinaryExponentiation(node as BinaryExpression):
        Write 'Math.pow('
        Visit node.Left
        Write ', '
        Visit node.Right
        Write ')'

    def BinaryMatch(node as BinaryExpression):
        type = TypeSystem.TypeSystemServices.GetExpressionType(node.Right)
        if type.ToString() == 'BooJs.Lang.RegExp':
            Visit node.Right
            Write '.test('
            Visit node.Left
            Write ')'
            return

        # handle strings
        Write '(-1 !== '
        Visit node.Left
        Write '.indexOf('
        Visit node.Right
        Write '))'

    def OnBinaryExpression(node as BinaryExpression):

        if node.Operator == BinaryOperatorType.Assign:
            BinaryAssign(node)
        elif node.Operator == BinaryOperatorType.Exponentiation:
            BinaryExponentiation(node)
        elif node.Operator == BinaryOperatorType.Match: # a =~ b
            BinaryMatch(node)
        elif node.Operator == BinaryOperatorType.NotMatch: # a !~ b
            # TODO: If we have a runtime we can match regexp too
            Write '(-1 === '
            Visit node.Left
            Write '.indexOf('
            Visit node.Right
            Write '))'
        elif node.Operator == BinaryOperatorType.NotMember: # a not in b -> !(a in b)
            Write '!('
            Visit node.Left
            Write ' in '
            Visit node.Right
            Write ')'
        elif node.Operator == BinaryOperatorType.TypeTest: # a isa type -> typeof a === 'type'  OR  a instanceof type
            # isa rhs is encoded in a typeof expression
            if node.Right isa TypeofExpression \
            and (node.Right as TypeofExpression).Type isa SimpleTypeReference:
                # TODO: We need to convert type names to JS ones somewhere
                # TODO: Shall we also check for instanceof Number, String, Array... ???
                type = (node.Right as TypeofExpression).Type as SimpleTypeReference

                if type.Name.IndexOf('Error') >= 0:
                    Visit node.Left
                    Write ' instanceof '
                    Visit node.Right
                else:
                    Write 'typeof '
                    Visit node.Left
                    Write " === "
                    if type.Name == 'bool':
                        Write "'boolean'"
                    elif type.Name == 'int' or type.Name == 'uint' or type.Name == 'double':
                        Write "'number'"
                    elif type.Name == 'void':
                        Write "'undefined'"
                    elif type.Name == 'callable':
                        Write "'function'"
                    else:
                        Write "'$(type.Name)'"

            else:
                Visit node.Left
                Write ' instanceof '
                Visit node.Right

        else:
            parens = NeedsParensAround(node)
            Write '(' if parens
            Visit node.Left
            Write " "
            Write GetBinaryOperatorText(node.Operator)
            Write " "
            Visit node.Right
            Write ')' if parens

    def OnSimpleTypeReference(node as SimpleTypeReference):
        # TODO: Why is this happending?
        if node.ToString() == 'System.Object' or node.ToString() == 'object':
            print 'WARNING: SimpleTypeReference = ', node
            return

        if node.Name.IndexOf('BooJs.Lang.') == 0:
            Write node.Name.Substring('BooJs.Lang.'.Length)
        else:
            Write node.Name

    def GetBinaryOperatorText(op as BinaryOperatorType):

        return '=' if op == BinaryOperatorType.Assign
        # Note: We use equality in value and type in JS
        return '==' if op == BinaryOperatorType.Equality
        return '!=' if op == BinaryOperatorType.Inequality
        return '+' if op == BinaryOperatorType.Addition
        return '-' if op == BinaryOperatorType.Subtraction
        return '*' if op == BinaryOperatorType.Multiply
        return '/' if op == BinaryOperatorType.Division
        return '%' if op == BinaryOperatorType.Modulus
        return '+=' if op == BinaryOperatorType.InPlaceAddition
        return '-=' if op == BinaryOperatorType.InPlaceSubtraction
        return '*=' if op == BinaryOperatorType.InPlaceMultiply
        return '%=' if op == BinaryOperatorType.InPlaceModulus
        return '/=' if op == BinaryOperatorType.InPlaceDivision
        return '&=' if op == BinaryOperatorType.InPlaceBitwiseAnd
        return '|=' if op == BinaryOperatorType.InPlaceBitwiseOr
        return '^=' if op == BinaryOperatorType.InPlaceExclusiveOr
        return '>' if op == BinaryOperatorType.GreaterThan
        return '>=' if op == BinaryOperatorType.GreaterThanOrEqual
        return '<' if op == BinaryOperatorType.LessThan
        return '<=' if op == BinaryOperatorType.LessThanOrEqual

        # TODO: Does it work most of the time???
        return 'in' if op == BinaryOperatorType.Member

        return '===' if op == BinaryOperatorType.ReferenceEquality
        return '!==' if op == BinaryOperatorType.ReferenceInequality

        return 'instanceof' if op == BinaryOperatorType.TypeTest
        return '||' if op == BinaryOperatorType.Or
        return '&&' if op == BinaryOperatorType.And

        return '|' if op == BinaryOperatorType.BitwiseOr
        return '&' if op == BinaryOperatorType.BitwiseAnd
        return '^' if op == BinaryOperatorType.ExclusiveOr
        return '<<' if op == BinaryOperatorType.ShiftLeft
        return '>>' if op == BinaryOperatorType.ShiftRight
        return '<<=' if op == BinaryOperatorType.InPlaceShiftLeft
        return '>>=' if op == BinaryOperatorType.InPlaceShiftRight

        raise 'Operator $(op) is not implemented'

    def NeedsParensAround(node as Expression):
        t = node.NodeType
        return false if t == NodeType.StringLiteralExpression
        return false if t == NodeType.CharLiteralExpression
        return false if t == NodeType.BoolLiteralExpression
        return false if t == NodeType.IntegerLiteralExpression
        return false if t == NodeType.DoubleLiteralExpression
        return false if t == NodeType.NullLiteralExpression
        return false if t == NodeType.ReferenceExpression
        return false if t == NodeType.ListLiteralExpression
        return false if t == NodeType.ArrayLiteralExpression
        return false if t == NodeType.MethodInvocationExpression
        return false if t == NodeType.UnaryExpression

        # TODO: Not very sure about this
        if node.ParentNode:
            t = node.ParentNode.NodeType
            return false if t == NodeType.ExpressionStatement
            #return false if t == NodeType.IfStatement
            #return false if t == NodeType.WhileStatement
            #return false if t == NodeType.UnlessStatement

        return true

    def WriteCallableDefinitionHeader(keyword as string, node as CallableDefinition):
        # TODO: Inspect params and return to generate type annotations for Closure
        WriteIndented keyword
        Map node
        Write node.Name
        WriteParameterList(node.Parameters, '(', ')')

    def WriteParameterList(params as ParameterDeclarationCollection, st, ed):
        Write(st)
        i = 0
        for param in params:
            if i > 0:
                Write(', ')
            Visit(param)
            i++
        Write(ed)

    def OnParameterDeclaration(p as ParameterDeclaration):
        if p.IsParamArray: Write("*")
        Map(p)
        Write(p.Name);

    def OnEnumDefinition(node as EnumDefinition):
        # TODO: Prefix with namespace
        Write 'var '

        Map node
        Write "$(node.FullName) = "
        WriteOpenBrace
        first = true
        for member as EnumMember in node.Members:
            assert member.Initializer != null, 'Enum definition without an initializer value!'
            WriteLine ',' if not first
            WriteIndented
            Map member
            Write member.Name
            Write ': '
            Visit member.Initializer
            first = false

        WriteLine
        WriteCloseBrace

    def ___OnClassDefinition(node as ClassDefinition):
        Write "$(node.Name) = function()"
        WriteOpenBrace

        if len(node.BaseTypes):
            Write '/* extends '
            WriteCommaSeparatedList(node.BaseTypes)
            Write '*/'
            WriteLine

        statics = []
        methods = []
        for member as TypeMember in node.Members:
            # Static members are defined outside the constructor
            if member.IsStatic:
                statics.Push(member)
                continue

            # Call the constructor method
            if member isa Constructor:
                WriteIndented 'this.constructor.apply(this, arguments);'
                WriteLine

            # Collect to define the prototype
            if member isa Method:
                methods.Push(member)
                continue

            WriteIndented
            Visit(member)
            WriteLine()

        WriteCloseBrace

        # Setup the static fields
        for member as TypeMember in statics:
            # Inline the static constructor
            if member isa Constructor:
                Visit((member as Constructor).Body)
                continue

            WriteIndented "$(member.FullName) = "
            Visit(member)
            WriteLine

        # Setup prototype
        for member as TypeMember in methods:
            WriteIndented member.DeclaringType.FullName
            Write ".prototype.$(member.Name) = "
            Visit(member)
            WriteLine

    def OnField(f as Field):
        # Not supported
        return

    def OnConstructor(node as Constructor):
        # Not supported
        return

    def WriteTypeDefinition(keyword, node as TypeDefinition):
        raise 'This is not yet implemented'

        #WriteAttributes(node.Attributes, true)
        #WriteModifiers(node)
        WriteIndented
        Write keyword
        Write ' '

        splice = node.ParentNode as SpliceTypeMember
        if splice:
            #WriteSplicedExpression(splice.NameExpression)
            pass
        else:
            Write(node.Name)

        #if len(node.GenericParameters):
        #    WriteGenericParameterList(node.GenericParameters);

        if len(node.BaseTypes):
            Write("(")
            WriteCommaSeparatedList(node.BaseTypes)
            Write(")")

        WriteLine(":")
        if len(node.Members):
            for member as TypeMember in node.Members:
                print member.NodeType
                Visit(member)
                WriteLine()
        else:
            Write 'pass'

    def OnExpressionPair(pair as ExpressionPair):
        Visit pair.First
        Write ': '
        Visit pair.Second

    def WriteStringLiteral(text as string):
        WriteStringLiteral text, "'"

    def WriteStringLiteral(text as string, quote as string):
        Write quote
        WriteStringContent text, quote
        Write quote

    def WriteStringContent(text as string, quote as string):
        for ch in text:
            str = ch.ToString()  # Convet to string from char
            if str == '\r':
                Write '\\r'
            elif str == '\n':
                Write '\\n'
            elif str == '\t':
                Write '\\t'
            elif str == '\0':
                Write '\\0'
            elif str == '\\':
                Write '\\\\'
            elif str == "'" and str == quote:
                Write "\\'"
            elif str == '"' and str == quote:
                Write '\\"'
            else:
                Write(str)

class PrintBooJs(PrintBoo):

    override def Run():
        visitor = BooJsPrinterVisitor(OutputWriter)
        visitor.Initialize(Context)
        visitor.Print(CompileUnit);


Support automatic conversion of named params to hash literals on method invocations

namespace BooJs.Compiler.Steps

import Boo.Lang.Environments
import Boo.Lang.Compiler.Steps
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem(ExternalMethod, IExternalEntity, IMethod,
                                    Reflection, Internal, IType,
                                    BuiltinFunction, BuiltinFunctionType)
import Boo.Lang.Compiler.Steps.Generators(GeneratorItemTypeInferrer)

class OverrideProcessMethodBodies(ProcessMethodBodiesWithDuckTyping):
""" Overrides some methods of the step to skip some modification made originally
"""

    class Pmb(IQuackFu):
    """ Uses reflection to call private methods in the ancestor class ProcessMethodBodies via a
        IQuackFu api.
    """
        pmb = typeof(ProcessMethodBodies)
        instance as ProcessMethodBodies
        def constructor(instance):
            self.instance = instance

        def QuackGet(prop as string, args as (object)):
            pass
        def QuackSet(prop as string, args as (object), val as object):
            pass
        def QuackInvoke(method as string, params as (object)) as object:
            types = array(System.Type, param.GetType() for param in params)
            mi = pmb.GetMethod(method, BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
                               null, types, null)
            if not mi:
                raise 'Private method {0} not found' % method
            return mi.Invoke(instance, params)

    # Obtain an instance to call ProcessMethodBodies private methods
    pmb = Pmb(self)

    override def Initialize(context as Boo.Lang.Compiler.CompilerContext):
        super(context)

    protected def IsMethod(node as Expression):
        # Make sure it's resolved
        Visit node

        entity = node.Entity
        return false if not entity
        if entity.EntityType == Boo.Lang.Compiler.TypeSystem.EntityType.Method:
            return true
        ambiguous = entity as Boo.Lang.Compiler.TypeSystem.Ambiguous
        return ambiguous and ambiguous.AllEntitiesAre(Boo.Lang.Compiler.TypeSystem.EntityType.Method)

    override def OnMethodInvocationExpression(node as MethodInvocationExpression):
        # Convert named arguments in method invocations to a hash literal
        if len(node.NamedArguments) and IsMethod(node.Target):
            h = HashLiteralExpression(node.NamedArguments[0].LexicalInfo)
            for arg in node.NamedArguments:
                arg.First = StringLiteralExpression(arg.LexicalInfo, (arg.First as ReferenceExpression).Name)
                h.Items.Add(arg)

            node.Arguments.Add(h)
            node.NamedArguments.Clear()

        super(node)

        # HACK: The ICallable interface declares a generic Call method with object arguments
        #       and return type. In order to support jQuery style APIs we detect the ICallable
        #       trying to modify it by using a better match among the methods named Call in
        #       the declarting type.
        # TODO: Perhaps it's better to keep ICallable implementation as is and use an attribute
        #       or a custom interface to signal this behaviour.
        target = node.Target as MemberReferenceExpression
        if target and target.Entity == MethodCache.ICallable_Call:
            # Find the original declaring type and fetch all its Call methods
            type = target.Target.ExpressionType as Reflection.ExternalType
            methods = List[of IMethod]()
            for member in type.GetMembers():
                if member isa ExternalMethod and member.Name == 'Call':
                    methods.Add(member)

            # Resolve the best match among the Call methods for the given params
            args = (node.Arguments[0] as ArrayLiteralExpression).Items
            resolved as ExternalMethod = CallableResolutionService.ResolveCallableReference(args, methods.ToArray())
            if resolved:
                BindExpressionType(node, resolved.ReturnType)
                BindExpressionType(node.Target, resolved.Type)

        # Detect invokes for internal callables
        # TODO: We could move this to a custom step in order to allow it to be optional
        #       In debug mode we might want to dispatch via our runtime to detect and
        #       properly report errors.
        if target and target.Entity:
            targetType = target.Entity as Internal.InternalMethod
            if targetType:
                invoke as IMethod = ResolveMethod(targetType.DeclaringType, 'Invoke')
                if invoke is targetType:
                    node.Target = target.Target

    override def LeaveUnaryExpression(node as UnaryExpression):
        # Increment/Decrement operators are resolved using a fairly complex eval. Since
        # JS supports this operators natively we can simplify the case by just binding
        # the correct type to the expression.
        if node.Operator in (UnaryOperatorType.Increment, UnaryOperatorType.Decrement,
                             UnaryOperatorType.PostDecrement, UnaryOperatorType.PostIncrement):
            # TODO: This doesn't take into account any operator overloading logic

            # Bind the type of the operand to the operation
            node.ExpressionType = GetExpressionType(node.Operand)
            return

        # Fall back to the original logic
        super(node)

    override def ProcessBuiltinInvocation(node as MethodInvocationExpression, func as BuiltinFunction):
        # Handle len(val)
        if func.FunctionType == BuiltinFunctionType.Len:
            result as Expression
            target = node.Arguments[0]

            # Check if the target has a 'length' property
            exptype = target.ExpressionType as Reflection.ExternalType
            if exptype:
                field = NameResolutionService.ResolveMember(exptype, 'length', Boo.Lang.Compiler.TypeSystem.EntityType.Field)
                if field:
                    result = MemberReferenceExpression(node.LexicalInfo, target, 'length')
                    result.ExpressionType = TypeSystemServices.IntType
                    node.ParentNode.Replace(node, result)
                    return

            # Otherwise use a runtime helper
            lenfn = NameResolutionService.ResolveMethod(TypeSystemServices.RuntimeServicesType, 'Len')
            result = CodeBuilder.CreateMethodInvocation(lenfn, target)
            node.ParentNode.Replace(node, result)
            return

        super(node, func)

    override def LeaveDeclarationStatement(node as DeclarationStatement):
        # If the declaration has been annotated as global via the `global` macro
        # we must avoid generating a declaration for it, either removing it
        # or just setting a value to it if the used supplied an initializer
        decl = node.Declaration
        if decl.ContainsAnnotation('global'):
            if not decl.Type:
                decl.Type = CodeBuilder.CreateTypeReference(decl.LexicalInfo, TypeSystemServices.DuckType)

            type = GetType(decl.Type)
            entity as Internal.InternalLocal = DeclareLocal(node, decl.Name, type, false)
            entity.OriginalDeclaration = decl

            if node.Initializer:
                node.ReplaceBy(
                    ExpressionStatement(
                        CodeBuilder.CreateAssignment(
                            node.LexicalInfo,
                            CodeBuilder.CreateReference(entity),
                            node.Initializer)
                        )
                    )
            else:
                (node.ParentNode as Block).Statements.Remove(node)

            return

        super(node)

    override protected def BindBinaryExpression(node as BinaryExpression):
        # Boo would directly allow all arithmetic on number types. We have to
        # specifically process those that are not valid in javascript

        ltype = GetExpressionType(node.Left)
        rtype = GetExpressionType(node.Right)

        if node.Operator == BinaryOperatorType.Exponentiation:
            if not pmb.ResolveOperator(node):
                pmb.InvalidOperatorForTypes(node)
        # Handle integer division
        elif node.Operator == BinaryOperatorType.Division and \
             TypeSystemServices.IsIntegerNumber(ltype) and \
             TypeSystemServices.IsIntegerNumber(rtype):

             if not pmb.ResolveOperator(node):
                pmb.InvalidOperatorForTypes(node)
        else:
            super(node)

    virtual protected def GetGeneratorReturnType(generator as Internal.InternalMethod) as IType:
        # TODO: DO WE NEED THIS?

        // Make method return a generic IEnumerable
        itemType = my(GeneratorItemTypeInferrer).GeneratorItemTypeFor(generator)
        if TypeSystemServices.VoidType == itemType:
            // circunvent exception in MakeGenericType
            return TypeSystemServices.ErrorEntity

        enumerableType = (TypeSystemServices as BooJs.Compiler.TypeSystem.TypeSystemServices).IGeneratorGenericType
        return enumerableType.GenericInfo.ConstructType(itemType)

namespace BooJs.Compiler.Steps

import Boo.Lang.Environments
import Boo.Lang.Compiler.Steps
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem(ExternalMethod, IExternalEntity, IMethod,
                                    Reflection, Internal, IType,
                                    BuiltinFunction, BuiltinFunctionType)
import Boo.Lang.Compiler.Steps.Generators(GeneratorItemTypeInferrer)

class OverrideProcessMethodBodies(ProcessMethodBodiesWithDuckTyping):
""" Overrides some methods of the step to skip some modification made originally
"""

    class Pmb(IQuackFu):
    """ Uses reflection to call private methods in the ancestor class ProcessMethodBodies via a
        IQuackFu api.
    """
        pmb = typeof(ProcessMethodBodies)
        instance as ProcessMethodBodies
        def constructor(instance):
            self.instance = instance

        def QuackGet(prop as string, args as (object)):
            pass
        def QuackSet(prop as string, args as (object), val as object):
            pass
        def QuackInvoke(method as string, params as (object)) as object:
            types = array(System.Type, param.GetType() for param in params)
            mi = pmb.GetMethod(method, BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
                               null, types, null)
            if not mi:
                raise 'Private method {0} not found' % method
            return mi.Invoke(instance, params)

    # Obtain an instance to call ProcessMethodBodies private methods
    pmb = Pmb(self)

    override def Initialize(context as Boo.Lang.Compiler.CompilerContext):
        super(context)

    override def OnMethodInvocationExpression(node as MethodInvocationExpression):

        super(node)

        # HACK: The ICallable interface declares a generic Call method with object arguments
        #       and return type. In order to support jQuery style APIs we detect the ICallable
        #       trying to modify it by using a better match among the methods named Call in
        #       the declarting type.
        # TODO: Perhaps it's better to keep ICallable implementation as is and use an attribute
        #       or a custom interface to signal this behaviour.
        target = node.Target as MemberReferenceExpression
        if target and target.Entity == MethodCache.ICallable_Call:
            # Find the original declaring type and fetch all its Call methods
            type = target.Target.ExpressionType as Reflection.ExternalType
            methods = List[of IMethod]()
            for member in type.GetMembers():
                if member isa ExternalMethod and member.Name == 'Call':
                    methods.Add(member)

            # Resolve the best match among the Call methods for the given params
            args = (node.Arguments[0] as ArrayLiteralExpression).Items
            resolved as ExternalMethod = CallableResolutionService.ResolveCallableReference(args, methods.ToArray())
            if resolved:
                BindExpressionType(node, resolved.ReturnType)
                BindExpressionType(node.Target, resolved.Type)

        # Detect invokes for internal callables
        # TODO: We could move this to a custom step in order to allow it to be optional
        #       In debug mode we might want to dispatch via our runtime to detect and
        #       properly report errors.
        if target and target.Entity:
            targetType = target.Entity as Internal.InternalMethod
            if targetType:
                invoke as IMethod = ResolveMethod(targetType.DeclaringType, 'Invoke')
                if invoke is targetType:
                    node.Target = target.Target

    override def LeaveUnaryExpression(node as UnaryExpression):
        # Increment/Decrement operators are resolved using a fairly complex eval. Since
        # JS supports this operators natively we can simplify the case by just binding
        # the correct type to the expression.
        if node.Operator in (UnaryOperatorType.Increment, UnaryOperatorType.Decrement,
                             UnaryOperatorType.PostDecrement, UnaryOperatorType.PostIncrement):
            # TODO: This doesn't take into account any operator overloading logic

            # Bind the type of the operand to the operation
            node.ExpressionType = GetExpressionType(node.Operand)
            return

        # Fall back to the original logic
        super(node)

    override def ProcessBuiltinInvocation(node as MethodInvocationExpression, func as BuiltinFunction):
        # Handle len(val)
        if func.FunctionType == BuiltinFunctionType.Len:
            result as Expression
            target = node.Arguments[0]

            # Check if the target has a 'length' property
            exptype = target.ExpressionType as Reflection.ExternalType
            if exptype:
                field = NameResolutionService.ResolveMember(exptype, 'length', Boo.Lang.Compiler.TypeSystem.EntityType.Field)
                if field:
                    result = MemberReferenceExpression(node.LexicalInfo, target, 'length')
                    result.ExpressionType = TypeSystemServices.IntType
                    node.ParentNode.Replace(node, result)
                    return

            # Otherwise use a runtime helper
            lenfn = NameResolutionService.ResolveMethod(TypeSystemServices.RuntimeServicesType, 'Len')
            result = CodeBuilder.CreateMethodInvocation(lenfn, target)
            node.ParentNode.Replace(node, result)
            return

        super(node, func)

    override def LeaveDeclarationStatement(node as DeclarationStatement):
        # If the declaration has been annotated as global via the `global` macro
        # we must avoid generating a declaration for it, either removing it
        # or just setting a value to it if the used supplied an initializer
        decl = node.Declaration
        if decl.ContainsAnnotation('global'):
            if not decl.Type:
                decl.Type = CodeBuilder.CreateTypeReference(decl.LexicalInfo, TypeSystemServices.DuckType)

            type = GetType(decl.Type)
            entity as Internal.InternalLocal = DeclareLocal(node, decl.Name, type, false)
            entity.OriginalDeclaration = decl

            if node.Initializer:
                node.ReplaceBy(
                    ExpressionStatement(
                        CodeBuilder.CreateAssignment(
                            node.LexicalInfo,
                            CodeBuilder.CreateReference(entity),
                            node.Initializer)
                        )
                    )
            else:
                (node.ParentNode as Block).Statements.Remove(node)

            return

        super(node)

    override protected def BindBinaryExpression(node as BinaryExpression):
        # Boo would directly allow all arithmetic on number types. We have to
        # specifically process those that are not valid in javascript

        ltype = GetExpressionType(node.Left)
        rtype = GetExpressionType(node.Right)

        if node.Operator == BinaryOperatorType.Exponentiation:
            if not pmb.ResolveOperator(node):
                pmb.InvalidOperatorForTypes(node)
        # Handle integer division
        elif node.Operator == BinaryOperatorType.Division and \
             TypeSystemServices.IsIntegerNumber(ltype) and \
             TypeSystemServices.IsIntegerNumber(rtype):

             if not pmb.ResolveOperator(node):
                pmb.InvalidOperatorForTypes(node)
        else:
            super(node)

    virtual protected def GetGeneratorReturnType(generator as Internal.InternalMethod) as IType:
        # TODO: DO WE NEED THIS?

        // Make method return a generic IEnumerable
        itemType = my(GeneratorItemTypeInferrer).GeneratorItemTypeFor(generator)
        if TypeSystemServices.VoidType == itemType:
            // circunvent exception in MakeGenericType
            return TypeSystemServices.ErrorEntity

        enumerableType = (TypeSystemServices as BooJs.Compiler.TypeSystem.TypeSystemServices).IGeneratorGenericType
        return enumerableType.GenericInfo.ConstructType(itemType)


don't reuse the grammars

don't reuse the grammars

import Boo.OMeta
import Boo.Adt
import Boo.PatternMatching

data Exp = Const(value as int) | Infix(operator as string, left as Exp, right as Exp)

ometa E:
	num = ++digit >> value ^ Const(int.Parse(join(value, '')))
	exp = sum | fac
	sum = (fac >> x, '+', fac >> y) ^ Infix("+", x, y)
	fac = mult | atom
	mult = (atom >> x,'*', atom >> y) ^ Infix("*", x, y)
	atom = num | parens
	parens = ('(', exp >> value, ')') ^ value

ometa XE < E:
	fac = division | super
	division = (atom >> x, '/', atom >> y) ^ Infix("/", x, y)

// See, Mom! No visitors!
ometa Evaluator:
	eval = const | infix
	const = Const(value) ^ value
	infix = sum | mult
	sum = Infix(operator: "+", left: eval >> l, right: eval >> r) ^ add(l, r)
	mult = Infix(operator: "*", left: eval >> l, right: eval >> r) ^ multiply(l, r)
	def add(x as int, y as int):
		return x + y
	def multiply(x as int, y as int):
		return x * y

ometa XEvaluator < Evaluator:
	eval = division | super
	division = Infix(operator: "/", left: eval >> l, right: eval >> r) ^ divide(l, r)
	def divide(left as int, right as int):
		return left / right

while true:
	line = prompt("> ")
	if string.IsNullOrEmpty(line) or line == "/q": break
	match m=XE().Apply('exp', OMetaInput.For(line)):
		case SuccessfulMatch(Value):
			print XEvaluator().eval(OMetaInput.Singleton(Value))
		otherwise:
			print m

import Boo.OMeta
import Boo.Adt
import Boo.PatternMatching

data Exp = Const(value as int) | Infix(operator as string, left as Exp, right as Exp)

ometa E:
	num = ++digit >> value ^ Const(int.Parse(join(value, '')))
	exp = sum | fac
	sum = (fac >> x, '+', fac >> y) ^ Infix("+", x, y)
	fac = mult | atom
	mult = (atom >> x,'*', atom >> y) ^ Infix("*", x, y)
	atom = num | parens
	parens = ('(', exp >> value, ')') ^ value

ometa XE < E:
	fac = division | super
	division = (atom >> x, '/', atom >> y) ^ Infix("/", x, y)

ometa Evaluator:
	eval = const | infix
	const = Const(value) ^ value
	infix = sum | mult
	sum = Infix(operator: "+", left: eval >> l, right: eval >> r) ^ add(l, r)
	mult = Infix(operator: "*", left: eval >> l, right: eval >> r) ^ multiply(l, r)
	def add(x as int, y as int):
		return x + y
	def multiply(x as int, y as int):
		return x * y

ometa XEvaluator < Evaluator:
	eval = division | super
	division = Infix(operator: "/", left: eval >> l, right: eval >> r) ^ divide(l, r)
	def divide(left as int, right as int):
		return left / right

p = XE()
e = XEvaluator()
while true:
	line = prompt("> ")
	if string.IsNullOrEmpty(line) or line == "/q": break
	match m=p.Apply('exp', OMetaInput.For(line)):
		case SuccessfulMatch(Value):
			print e.eval(OMetaInput.Singleton(Value))
		otherwise:
			print m


just checking if patches are being sent to googlegroup

import org.eclipse.swt
import org.eclipse.swt.widgets

display = Display()
shell = Shell(display)
shell.setText("Hello!")
shell.setSize(640, 480)
shell.open()

while not shell.isDisposed():
	if not display.readAndDispatch():
		display.sleep()

display.dispose()

import org.eclipse.swt
import org.eclipse.swt.widgets

display = Display()
shell = Shell(display)
shell.setText("Hello!")
shell.setSize(200, 200)
shell.open()

while not shell.isDisposed():
	if not display.readAndDispatch():
		display.sleep()

display.dispose()