166 lines
5.0 KiB
Python
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
|