old_contents:
namespace BooJs.Compiler.Steps

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

class ProcessGoto(AbstractTransformerCompilerStep):
"""
    Process labels and goto statements

    The supported uses are very limited. It's only possible to jump to a label
    previously defined in the same function. No jumps to forward labels are
    allowed.

    Even if fully supporting goto statements with forward jumping is theoretically
    possible (similarly on how generators are transformed for example), it would be
    difficult to implement for the benefits it provides.

    TODO: Check implementation constraints. Referenced label can only
          be present in the same method and above the goto statement
"""
    override def Run():
        if len(Errors) > 0:
            return
        Visit CompileUnit

    def OnLabelStatement(node as LabelStatement):
        parent = node.ParentNode as Block
        index = parent.Statements.IndexOf(node)

        loop = [|
            while true: pass
        |]
        loop.Block.Statements = parent.Statements.PopRange(index+1)
        # We need to break out of the loop when we reach the end :)
        loop.Block.Statements.Add(BreakStatement())

        parent.Statements.Add(loop)

new_contents:
namespace BooJs.Compiler.Steps

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

class ProcessGoto(AbstractTransformerCompilerStep):
"""
    Process labels and goto statements

    The supported uses are very limited. It's only possible to jump to a label
    previously defined in the same function. No jumps to forward labels are
    allowed.

    Even if fully supporting goto statements with forward jumping is theoretically
    possible (similarly on how generators are transformed for example), it would be
    difficult to implement for the benefits it provides.

    TODO: Check implementation constraints. Referenced label can only
          be present in the same method and above the goto statement
"""
    override def Run():
        if len(Errors) > 0:
            return
        Visit CompileUnit

    def OnLabelStatement(node as LabelStatement):
        # Make sure we only process the statement once
        if node.ContainsAnnotation(self):
            return

        node.Annotate(self)

        parent = node.ParentNode as Block
        index = parent.Statements.IndexOf(node)

        loop = [|
            while true: pass
        |]
        loop.Block.Statements = parent.Statements.PopRange(index+1)
        # We need to break out of the loop when we reach the end :)
        loop.Block.Statements.Add(BreakStatement())

        parent.Statements.Add(loop)

subject: Make sure Goto is only processed once

message: Make sure Goto is only processed once

license: mit


old_contents:
namespace BooJs.Compiler.Steps

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

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

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

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

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

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

new_contents:
namespace BooJs.Compiler.Steps

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

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

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

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

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

        super(node)

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

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

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

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

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

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

subject: Use sequence instead of self execution functions