Beispiel #1
0
def call_statement(l, loc):
    l.expect_noblock('call statment')

    if l.keyword('expression'):
        expression = True
        target = l.require(l.simple_expression)

    else:
        expression = False
        target = l.require(l.name)

    # Optional pass, to let someone write:
    # call expression foo pass (bar, baz)
    l.keyword('pass')

    arguments = parse_arguments(l)

    rv = [ast.Call(loc, target, expression, arguments)]

    if l.keyword('from'):
        name = l.require(l.name)
        rv.append(ast.Label(loc, name, [], None))
    else:
        rv.append(ast.Pass(loc))

    l.expect_eol()
    l.advance()

    return rv
Beispiel #2
0
def label_statement(l, loc):
    name = l.require(l.name)

    parameters = parse_parameters(l)

    l.require(':')
    l.expect_eol()

    # Optional block here. It's empty if no block is associated with
    # this statement.
    block = parse_block(l.subblock_lexer())

    l.advance()
    return ast.Label(loc, name, block, parameters)
Beispiel #3
0
def menu_statement(l, loc):
    l.expect_block('menu statement')
    label = l.name()
    l.require(':')
    l.expect_eol()

    menu = parse_menu(l, loc)

    l.advance()

    rv = []

    if label:
        rv.append(ast.Label(loc, label, [], None))

    rv.extend(menu)

    return rv
Beispiel #4
0
def parse_statement(l):
    """
    This parses a Ren'Py statement. l is expected to be a Ren'Py lexer
    that has been advanced to a logical line. This function will
    advance l beyond the last logical line making up the current
    statement, and will return an AST object representing this
    statement, or a list of AST objects representing this statement.
    """

    # Store the current location.
    loc = l.get_location()

    ### If statement
    if l.keyword('if'):
        entries = []

        condition = l.require(l.python_expression)
        l.require(':')
        l.expect_eol()
        l.expect_block('if statement')

        block = parse_block(l.subblock_lexer())

        entries.append((condition, block))

        l.advance()

        while l.keyword('elif'):

            condition = l.require(l.python_expression)
            l.require(':')
            l.expect_eol()
            l.expect_block('elif clause')

            block = parse_block(l.subblock_lexer())

            entries.append((condition, block))

            l.advance()

        if l.keyword('else'):
            l.require(':')
            l.expect_eol()
            l.expect_block('else clause')

            block = parse_block(l.subblock_lexer())

            entries.append(('True', block))

            l.advance()

        return ast.If(loc, entries)

    if l.keyword('elif'):
        l.error('elif clause must be associated with an if statement.')

    if l.keyword('else'):
        l.error('else clause must be associated with an if statement.')

    ### While statement
    if l.keyword('while'):
        condition = l.require(l.python_expression)
        l.require(':')
        l.expect_eol()
        l.expect_block('while statement')
        block = parse_block(l.subblock_lexer())
        l.advance()

        return ast.While(loc, condition, block)

    ### Pass statement
    if l.keyword('pass'):
        l.expect_noblock('pass statement')
        l.expect_eol()
        l.advance()

        return ast.Pass(loc)

    ### Menu statement.
    if l.keyword('menu'):
        l.expect_block('menu statement')
        label = l.name()
        l.require(':')
        l.expect_eol()

        menu = parse_menu(l, loc)

        l.advance()

        rv = []

        if label:
            rv.append(ast.Label(loc, label, [], None))

        rv.extend(menu)

        return rv

    ### Return statement.
    if l.keyword('return'):
        l.expect_noblock('return statement')

        rest = l.rest()
        if not rest:
            rest = None

        l.expect_eol()
        l.advance()

        return ast.Return(loc, rest)

    ### Jump statement
    if l.keyword('jump'):
        l.expect_noblock('jump statement')

        if l.keyword('expression'):
            expression = True
            target = l.require(l.simple_expression)
        else:
            expression = False
            target = l.require(l.name)

        l.expect_eol()
        l.advance()

        return ast.Jump(loc, target, expression)

    ### Call/From statement.
    if l.keyword('call'):
        l.expect_noblock('call statment')

        if l.keyword('expression'):
            expression = True
            target = l.require(l.simple_expression)

        else:
            expression = False
            target = l.require(l.name)

        # Optional pass, to let someone write:
        # call expression foo pass (bar, baz)
        l.keyword('pass')

        arguments = parse_arguments(l)

        rv = [ast.Call(loc, target, expression, arguments)]

        if l.keyword('from'):
            name = l.require(l.name)
            rv.append(ast.Label(loc, name, [], None))
        else:
            rv.append(ast.Pass(loc))

        l.expect_eol()
        l.advance()

        return rv

    ### Scene statement.
    if l.keyword('scene'):

        if l.keyword('onlayer'):
            layer = l.require(l.name)
        else:
            layer = "master"

        # Empty.
        if l.eol():
            l.advance()
            return ast.Scene(loc, None, layer)

        imspec = parse_image_specifier(l)
        stmt = ast.Scene(loc, imspec, imspec[4])
        rv = parse_with(l, stmt)

        if l.match(':'):
            stmt.atl = renpy.atl.parse_atl(l.subblock_lexer())
        else:
            l.expect_noblock('scene statement')

        l.expect_eol()
        l.advance()

        return rv

    ### Show statement.
    if l.keyword('show'):
        imspec = parse_image_specifier(l)
        stmt = ast.Show(loc, imspec)
        rv = parse_with(l, stmt)

        if l.match(':'):
            stmt.atl = renpy.atl.parse_atl(l.subblock_lexer())
        else:
            l.expect_noblock('show statement')

        l.expect_eol()
        l.advance()

        return rv

    ### Hide statement.
    if l.keyword('hide'):
        imspec = parse_image_specifier(l)
        rv = parse_with(l, ast.Hide(loc, imspec))

        l.expect_eol()
        l.expect_noblock('hide statement')
        l.advance()

        return rv

    ### With statement.
    if l.keyword('with'):
        expr = l.require(l.simple_expression)
        l.expect_eol()
        l.expect_noblock('with statement')
        l.advance()

        return ast.With(loc, expr)

    ### Image statement.
    if l.keyword('image'):

        name = parse_image_name(l)

        if l.match(':'):
            l.expect_eol()
            expr = None
            atl = renpy.atl.parse_atl(l.subblock_lexer())
        else:
            l.require('=')
            expr = l.rest()
            atl = None
            l.expect_noblock('image statement')

        rv = ast.Image(loc, name, expr, atl)

        if not l.init:
            rv = ast.Init(loc, [rv], 990)

        l.advance()

        return rv

    ### Define statement.
    if l.keyword('define'):

        priority = l.integer()
        if priority:
            priority = int(priority)
        else:
            priority = 0

        name = l.require(l.name)
        l.require('=')
        expr = l.rest()

        l.expect_noblock('define statement')

        rv = ast.Define(loc, name, expr)

        if not l.init:
            rv = ast.Init(loc, [rv], priority)

        l.advance()

        return rv

    ### Transform statement.
    if l.keyword('transform'):

        priority = l.integer()
        if priority:
            priority = int(priority)
        else:
            priority = 0

        name = l.require(l.name)
        parameters = parse_parameters(l)

        if parameters and (parameters.extrakw or parameters.extrapos):
            l.error(
                'transform statement does not take a variable number of parameters'
            )

        l.require(':')
        l.expect_eol()

        atl = renpy.atl.parse_atl(l.subblock_lexer())

        rv = ast.Transform(loc, name, atl, parameters)

        if not l.init:
            rv = ast.Init(loc, [rv], priority)

        l.advance()

        return rv

    ### One-line python statement.
    if l.match(r'\$'):
        python_code = l.rest()
        l.expect_noblock('one-line python statement')
        l.advance()

        return ast.Python(loc, python_code)

    ### Python block.
    if l.keyword('python'):

        hide = False
        early = False

        if l.keyword('early'):
            early = True

        if l.keyword('hide'):
            hide = True

        l.require(':')
        l.expect_block('python block')

        python_code = l.python_block()

        l.advance()

        if early:
            return ast.EarlyPython(loc, python_code, hide)
        else:
            return ast.Python(loc, python_code, hide)

    ### Label Statement
    if l.keyword('label'):
        name = l.require(l.name)

        parameters = parse_parameters(l)

        l.require(':')
        l.expect_eol()

        # Optional block here. It's empty if no block is associated with
        # this statement.
        block = parse_block(l.subblock_lexer())

        l.advance()
        return ast.Label(loc, name, block, parameters)

    ### Init Statement
    if l.keyword('init'):

        p = l.integer()

        if p:
            priority = int(p)
        else:
            priority = 0

        if l.keyword('python'):

            hide = False
            if l.keyword('hide'):
                hide = True

            l.require(':')
            l.expect_block('python block')

            python_code = l.python_block()

            l.advance()
            block = [ast.Python(loc, python_code, hide)]

        else:
            l.require(':')

            l.expect_eol()
            l.expect_block('init statement')

            block = parse_block(l.subblock_lexer(True))

            l.advance()

        return ast.Init(loc, block, priority)

    # Try parsing as a user-statement. If that doesn't work, revert and
    # try as a say.

    state = l.checkpoint()

    word = l.word()
    if (word, ) in renpy.statements.registry:
        text = l.text

        l.expect_noblock(word + ' statement')
        l.advance()

        renpy.exports.push_error_handler(l.error)
        try:
            rv = ast.UserStatement(loc, text)
        finally:
            renpy.exports.pop_error_handler()

        return rv

    l.revert(state)

    # Try parsing as the default statement.
    if () in renpy.statements.registry:
        text = l.text
        l.expect_noblock('default statement')
        l.advance()

        renpy.exports.push_error_handler(l.error)
        try:
            rv = ast.UserStatement(loc, text)
        finally:
            renpy.exports.pop_error_handler()

        return rv

    # The one and two arguement say statements are ambiguous in terms
    # of lookahead. So we first try parsing as a one-argument, then a
    # two-argument.

    # We're using the checkpoint from above.

    what = l.string()

    if l.keyword('with'):
        with_ = l.require(l.simple_expression)
    else:
        with_ = None

    if what is not None and l.eol():
        # We have a one-argument say statement.
        l.expect_noblock('say statement')
        l.advance()
        return ast.Say(loc, None, what, with_)

    l.revert(state)

    # Try for a two-argument say statement.
    who = l.simple_expression()
    what = l.string()

    if l.keyword('with'):
        with_ = l.require(l.simple_expression)
    else:
        with_ = None

    if who and what is not None:
        l.expect_eol()
        l.expect_noblock('say statement')
        l.advance()
        return ast.Say(loc, who, what, with_)

    l.error('expected statement.')