コード例 #1
0
ファイル: _while.py プロジェクト: colinta/plywood
def _while(states, scope, arguments, block):
    if not len(block.lines):
        raise InvalidArguments('A block is required in `while`')
    if len(arguments.args) != 1 \
        or len(arguments.kwargs):
        raise InvalidArguments('`while` only accepts one conditional argument')
    var = arguments.args[0]

    retval = None
    while var.python_value(scope):
        if retval is None:
            retval = ''
        try:
            retval += str(block.python_value(scope))
        except BreakException as e:
            retval += e.retval
            break
        except ContinueException as e:
            retval += e.retval
            continue
    else:
        if retval is None:
            return [Continue(), EmptyState(), ElseState()], ''
        return [Continue(), ElseState()], retval
    return [Continue()], retval
コード例 #2
0
def define_block(states, scope, arguments, block):
    if not len(arguments.args):
        raise InvalidArguments('A block name is required in `block`')
    if len(arguments.args) != 1 or len(arguments.kwargs):
        raise InvalidArguments('`block` only accepts one argument')
    block_name = arguments.args[0].python_value(scope)
    scope['__blocks'][block_name] = block
    return states, ''
コード例 #3
0
ファイル: include.py プロジェクト: colinta/plywood
def include(states, scope, arguments, block):
    if len(arguments.args) != 1:
        raise InvalidArguments('`include` only accepts one argument')
    if len(block.lines):
        raise InvalidArguments('`include` does not accept a block')

    restore_scope = {}
    delete_scope = []
    if isinstance(scope['self'], PlywoodValue):
        context = scope['self'].python_value(scope)
    else:
        context = scope['self']

    if len(arguments.kwargs):
        kwargs = dict(
            (item.key.get_name(), item.value)
                for item in arguments.kwargs
                )
        for key, value in kwargs.items():
            if key in context:
                restore_scope[key] = context[key]
            else:
                delete_scope.append(key)
            context[key] = value

    if '__env' in scope:
        env = scope['__env']
    else:
        env = PlywoodEnv({'separator': ' '})

    template_name = arguments.args[0].python_value(scope)
    plywood = None
    for path in scope['__paths']:
        template_path = os.path.join(path, template_name) + '.ply'
        if template_path in env.includes:
            plywood = env.includes[template_path]
        elif os.path.exists(template_path):
            retval = ''
            with open(template_path) as f:
                input = f.read()
                plywood = Plywood(input)
                env.includes[template_path] = plywood
                # scope is not pushed/popped - `include` adds its variables to the local scope.

        if plywood:
            break

    if not plywood:
        raise Exception('Could not find template: {0!r}'.format(template_name))

    retval = plywood.run(context, env)

    if len(arguments.kwargs):
        for key, value in restore_scope.items():
            context[key] = value
        for key in delete_scope:
            del context[key]
    return states, retval
コード例 #4
0
def _import(states, scope, arguments, block):
    if len(arguments.kwargs):
        raise InvalidArguments('`import` does not accept keyword arguments')
    if len(block.lines):
        raise InvalidArguments('`import` does not accept a block')
    for arg in arguments.args:
        scope_name, import_name = join_module_names(arg)
        scope[scope_name] = __import__(import_name)
    return states, ''
コード例 #5
0
ファイル: _if.py プロジェクト: colinta/plywood
def _elif(states, scope, arguments, block):
    if not len(block.lines):
        raise InvalidArguments('A block is required in `elif`')
    if len(arguments.args) != 1:
        raise InvalidArguments(
            'A condition (and only one condition) is required in `elif`')
    if len(arguments.args) != 1 or len(arguments.kwargs):
        raise InvalidArguments('`elif` only accepts one argument')
    arg = arguments.args[0].python_value(scope)
    if arg:
        return [Continue()], block.get_value(scope)
    return [Continue(), ElseState()], ''
コード例 #6
0
ファイル: _for.py プロジェクト: colinta/plywood
def _for(states, scope, arguments, block):
    if not len(block.lines):
        raise InvalidArguments('A block is required in `for`')
    if len(arguments.args) != 1 \
        or len(arguments.kwargs) \
        or not isinstance(arguments.args[0], PlywoodOperator) \
        or arguments.args[0].operator != 'in':
        raise InvalidArguments('`for` only accepts an `in` operation')
    var = arguments.args[0].left
    if not isinstance(var, PlywoodVariable) and not isinstance(
            var, PlywoodParens):
        raise InvalidArguments(
            '`for` expects a variable name or tuple of variable names')
    if isinstance(var, PlywoodParens):
        if var.kwargs:
            raise InvalidArguments(
                'keyword arguments are not in appropriate in the list of  `for` variable names'
            )
        for arg in var.arguments:
            if not isinstance(arg, PlywoodVariable):
                raise InvalidArguments(
                    '`for` expects a variable name or tuple of variable names')
    iterator = arguments.args[0].right.python_value(scope)

    retval = None
    if not iterator:
        return [Continue(), EmptyState(), ElseState()], ''
    for for_value in iterator:
        if retval is None:
            retval = ''
        if isinstance(var, PlywoodVariable):
            varname = var.get_name()
            scope[varname] = for_value
        elif isinstance(var, PlywoodParens):
            raise Exception('huh?')
            # for_values should be a PlywoodList, PlywoodDict,
            # if len(var.arguments) !=
            # scope[]
            pass
        try:
            retval += str(block.python_value(scope))
        except BreakException as e:
            retval += e.retval
            break
        except ContinueException as e:
            retval += e.retval
            continue
    else:
        if retval is None:
            return [Continue(), EmptyState(), ElseState()], ''
        return [Continue(), ElseState()], retval
    return [Continue()], retval
コード例 #7
0
def _from(states, scope, arguments, block):
    if len(arguments.kwargs):
        raise InvalidArguments('`from` does not accept keyword arguments')
    if len(block.lines):
        raise InvalidArguments('`from` does not accept a block')
    if len(arguments.args) != 2:
        raise InvalidArguments(
            '`from` only accepts a module and a list of attributes to import')
    _, target = join_module_names(arguments.args[0])
    imports = arguments.args[1]
    if len(imports.args) == 1 and isinstance(imports.args[0], PlywoodParens):
        imports = imports.args[0]
    module = __import__(target)
    for var in imports.args:
        attr = var.get_name()
        scope[attr] = getattr(module, attr)
    return states, ''
コード例 #8
0
def extends(states, scope, arguments, block):
    if not len(arguments.args):
        raise InvalidArguments('A layout name is required in `extends`')
    if len(arguments.args) != 1:
        raise InvalidArguments('`extends` only accepts one argument')

    scope.push()
    yield_content = block.get_value(
        scope)  # executes the body, to define blocks
    scope[
        '__yield'] = yield_content  # makes the extends body available to the yield method

    # inside the extended layout, block => get_block
    scope['block'] = scope['get_block']

    # include the layout
    states, retval = include(states, scope, arguments,
                             PlywoodBlock(block.location, []))
    scope.pop()
    return states, retval
コード例 #9
0
def join_module_names(token, scope_name=None):
    if isinstance(token, PlywoodOperator) and token.operator == '.':
        if scope_name is None:
            scope_name = token.left.get_name()
        return scope_name, token.left.get_name() + '.' + join_module_names(
            token.right, scope_name)[1]
    if not isinstance(token, PlywoodVariable):
        raise InvalidArguments(
            'Only variable names are allowed in an import statement')
    if scope_name is None:
        scope_name = token.get_name()
    return scope_name, token.get_name()
コード例 #10
0
    def the_function(states, called_scope, called_arguments, called_block):
        args = called_arguments.args
        kwargs = called_arguments.kwargs
        local_arglist = [] + final_arglist
        called_scope.push()
        for plywood_kwarg in kwargs:
            local_value = plywood_kwarg.value.python_value(scope)
            local_var_name = plywood_kwarg.key.python_value(scope)
            if local_var_name in local_arglist:
                local_arglist.remove(local_var_name)
            else:
                raise InvalidArguments('Unknown keyword argument {0!r}'.format(local_var_name))
            called_scope[local_var_name] = local_value

        for plywood_value in args:
            local_value = plywood_value.python_value(called_scope)
            if not local_arglist:
                raise InvalidArguments('Too many arguments passed to {0}'.format(function_name))
            local_var_name = local_arglist.pop(0)
            called_scope[local_var_name] = local_value

        for local_var_name, local_value in defaults.items():
            if local_var_name in local_arglist:
                local_arglist.remove(local_var_name)
                called_scope[local_var_name] = local_value

        if local_arglist:
            raise InvalidArguments('Unassigned values: {0}'.format(', '.join(local_arglist)))

        def return_function(arg):
            raise ReturnException(arg)

        called_scope['return'] = PlywoodFunction(return_function)
        try:
            retval = block.get_value(called_scope)
        except ReturnException as e:
            retval = e.retval
        called_scope.pop()
        return [Continue()], retval
コード例 #11
0
def get_block(states, scope, arguments, block):
    if not len(arguments.args):
        raise InvalidArguments('A block name is required in `get_block`')
    if len(arguments.args) != 1 or len(arguments.kwargs):
        raise InvalidArguments('`get_block` only accepts one argument')
    # if a block is defined, it will be stored as the default
    block_name = arguments.args[0].python_value(scope)
    if block.lines:
        if block_name in scope['__blocks']:
            scope.push()
            scope['super'] = block.get_value(scope)
            scope['super'].suppress_nl = True
            retval = scope['__blocks'][block_name].get_value(scope)
            scope.pop()
        else:
            retval = block.get_value(scope)
    else:
        if block_name in scope['__blocks']:
            retval = scope['__blocks'][block_name].get_value(scope)
        else:
            retval = ''
    return states, retval
コード例 #12
0
def _def(states, scope, arguments, block):
    '''
    Example:
        def foo(bar, baz, quux='value')
    foo => name of function
    [bar, baz] => arguments, no default values.  These must be variable names.

    Sorry, no support for *args and **kwargs just yet.
    '''
    if not len(block.lines):
        raise InvalidArguments('A block is required in `def`')
    if len(arguments.args) != 1 \
        or len(arguments.kwargs) \
        or not isinstance(arguments.args[0], PlywoodCallOperator) \
        or arguments.args[0].operator != '()':
        raise InvalidArguments('`def` should be followed by a function definition')
    function_name = arguments.args[0].left.get_name()
    arglist = arguments.args[0].right.args
    kwarglist = arguments.args[0].right.kwargs
    final_arglist = []
    defaults = {}
    # all arglist.args should be a varname
    for var_name in arglist:
        if not isinstance(var_name, PlywoodVariable):
            raise InvalidArguments('`def` should be given a list of variable names.  '
                                   '{0!r} is invalid'.format(var_name.python_value(scope)))
        final_arglist.append(var_name.get_name())

    for kwarg in kwarglist:
        var_name = kwarg.key.python_value(scope)
        final_arglist.append(var_name)
        value = kwarg.value.python_value(scope)
        defaults[var_name] = value

    # Now we have to re-produce python's way of accepting arguments, but I'm
    # gonna get away with being sloppy about it...
    # First, any kwargs can be assigned, and removed from the final_arglist.
    # Then, args is scanned and values are assigned to corresponding names in
    # final_arglist.  If any values are left over in final_arglist, args, or
    # kwargs, something went wrong.
    #
    # The sloppy part comes because unlike python, you can specify args and
    # kwargs in pretty much any order.  All kwargs are assigned first, then
    # the args are assigned to whatever is left in the local_arglist, then
    # defaults.  Only after all that is local_arglist checked to make sure it is
    # empty.
    def the_function(states, called_scope, called_arguments, called_block):
        args = called_arguments.args
        kwargs = called_arguments.kwargs
        local_arglist = [] + final_arglist
        called_scope.push()
        for plywood_kwarg in kwargs:
            local_value = plywood_kwarg.value.python_value(scope)
            local_var_name = plywood_kwarg.key.python_value(scope)
            if local_var_name in local_arglist:
                local_arglist.remove(local_var_name)
            else:
                raise InvalidArguments('Unknown keyword argument {0!r}'.format(local_var_name))
            called_scope[local_var_name] = local_value

        for plywood_value in args:
            local_value = plywood_value.python_value(called_scope)
            if not local_arglist:
                raise InvalidArguments('Too many arguments passed to {0}'.format(function_name))
            local_var_name = local_arglist.pop(0)
            called_scope[local_var_name] = local_value

        for local_var_name, local_value in defaults.items():
            if local_var_name in local_arglist:
                local_arglist.remove(local_var_name)
                called_scope[local_var_name] = local_value

        if local_arglist:
            raise InvalidArguments('Unassigned values: {0}'.format(', '.join(local_arglist)))

        def return_function(arg):
            raise ReturnException(arg)

        called_scope['return'] = PlywoodFunction(return_function)
        try:
            retval = block.get_value(called_scope)
        except ReturnException as e:
            retval = e.retval
        called_scope.pop()
        return [Continue()], retval
    the_function.__name__ = function_name

    scope[function_name] = PlywoodRuntime(the_function)
    return [Continue()], ''
コード例 #13
0
def _yield(states, scope, arguments, block):
    if len(arguments.args) or len(arguments.kwargs) or len(block.lines):
        raise InvalidArguments(
            '`yield` does not accept any arguments or block')
    yield_content = scope.get('__yield', '')
    return states, yield_content
コード例 #14
0
ファイル: _if.py プロジェクト: colinta/plywood
def _else(states, scope, arguments, block):
    if not len(block.lines):
        raise InvalidArguments('A block is required in `else`')
    if len(arguments.args) or len(arguments.kwargs):
        raise InvalidArguments('`else` does not accept any arguments')
    return [Continue()], block.get_value(scope)
コード例 #15
0
def _open(states, scope, arguments, block):
    if len(block.lines):
        raise InvalidArguments('`import` does not accept a block')
    args = map(lambda arg: arg.python_value(scope), arguments.args)
    retval = open(*args)
    return states, retval