2013-07-19 11:59:01 +02:00

166 lines
5.0 KiB
Python

# -*- coding: utf8 -*-
"""
.. module:: lesscpy.plib.mixin
:synopsis: Mixin node.
Copyright (c)
See LICENSE for details.
.. moduleauthor:: Johann T. Mariusson <jtm@robot.is>
"""
import sys
import copy
import itertools
from .node import Node
from .block import Block
from .expression import Expression
from .variable import Variable
from lesscpy.lessc import utility
class Mixin(Node):
""" Mixin Node. Represents callable mixin types.
"""
def parse(self, scope):
"""Parse node
args:
scope (Scope): current scope
raises:
SyntaxError
returns:
self
"""
self.name, args, self.guards = self.tokens[0]
self.args = [a for a in utility.flatten(args) if a]
self.body = Block([None, self.tokens[1]], 0)
self.vars = list(utility.flatten([list(v.values())
for v in [s['__variables__']
for s in scope]]))
return self
def raw(self):
"""Raw mixin name
returns:
str
"""
return self.name.raw()
def parse_args(self, args, scope):
"""Parse arguments to mixin. Add them to scope
as variables. Sets upp special variable @arguments
as well.
args:
args (list): arguments
scope (Scope): current scope
raises:
SyntaxError
"""
arguments = list(zip(args, [' '] * len(args))) if args and args[0] else None
zl = itertools.zip_longest if sys.version_info[
0] == 3 else itertools.izip_longest
if self.args:
parsed = [v if hasattr(v, 'parse') else v
for v in copy.copy(self.args)]
args = args if isinstance(args, list) else [args]
vars = [self._parse_arg(var, arg, scope)
for arg, var in zl([a for a in args], parsed)]
for var in vars:
if var:
var.parse(scope)
if not arguments:
arguments = [v.value for v in vars if v]
if not arguments:
arguments = ''
Variable(['@arguments', None, arguments]).parse(scope)
def _parse_arg(self, var, arg, scope):
""" Parse a single argument to mixin.
args:
var (Variable object): variable
arg (mixed): argument
scope (Scope object): current scope
returns:
Variable object or None
"""
if isinstance(var, Variable):
# kwarg
if arg:
if utility.is_variable(arg[0]):
tmp = scope.variables(arg[0])
if not tmp:
return None
val = tmp.value
else:
val = arg
var = Variable(var.tokens[:-1] + [val])
else:
# arg
if utility.is_variable(var):
if arg is None:
raise SyntaxError('Missing argument to mixin')
elif utility.is_variable(arg[0]):
tmp = scope.variables(arg[0])
if not tmp:
return None
val = tmp.value
else:
val = arg
var = Variable([var, None, val])
else:
return None
return var
def parse_guards(self, scope):
"""Parse guards on mixin.
args:
scope (Scope): current scope
raises:
SyntaxError
returns:
bool (passes guards)
"""
if self.guards:
cor = True if ',' in self.guards else False
for g in self.guards:
if isinstance(g, list):
res = (g[0].parse(scope)
if len(g) == 1
else Expression(g).parse(scope))
if cor:
if res:
return True
elif not res:
return False
return True
def call(self, scope, args=[]):
"""Call mixin. Parses a copy of the mixins body
in the current scope and returns it.
args:
scope (Scope): current scope
args (list): arguments
raises:
SyntaxError
returns:
list or False
"""
ret = False
if args:
args = [[a.parse(scope)
if isinstance(a, Expression)
else a for a in arg]
if arg else arg
for arg in args]
try:
self.parse_args(args, scope)
except SyntaxError:
pass
else:
if self.parse_guards(scope):
body = self.body.copy()
ret = body.tokens[1]
if ret:
utility.rename(ret, scope, Block)
return ret