# -*- coding: utf8 -*- """ .. module:: lesscpy.plib.mixin :synopsis: Mixin node. Copyright (c) See LICENSE for details. .. moduleauthor:: Johann T. Mariusson """ 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