# -*- coding: utf8 -*- """ .. module:: lesscpy.plib.deferred :synopsis: Deferred mixin call. Copyright (c) See LICENSE for details. .. moduleauthor:: Johann T. Mariusson <jtm@robot.is> """ from .node import Node class Deferred(Node): def __init__(self, mixin, args, lineno=0): """This node represents mixin calls. The calls to these mixins are deferred until the second parse cycle. lessc.js allows calls to mixins not yet defined or known. args: mixin (Mixin): Mixin object args (list): Call arguments """ self.tokens = [mixin, args] self.lineno = lineno def parse(self, scope, error=False, depth=0): """ Parse function. We search for mixins first within current scope then fallback to global scope. The special scope.deferred is used when local scope mixins are called within parent mixins. If nothing is found we fallback to block-mixin as lessc.js allows calls to blocks and mixins to be inter-changable. clx: This method is a HACK that stems from poor design elsewhere. I will fix it when I have more time. args: scope (Scope): Current scope returns: mixed """ res = False ident, args = self.tokens ident.parse(scope) mixins = scope.mixins(ident.raw()) if not mixins: ident.parse(None) mixins = scope.mixins(ident.raw()) if depth > 64: raise SyntaxError('NameError `%s`' % ident.raw(True)) if not mixins: if scope.deferred: store = [t for t in scope.deferred.parsed[-1]] i = 0 while scope.deferred.parsed[-1]: scope.current = scope.deferred ident.parse(scope) mixins = scope.mixins(ident.raw()) scope.current = None if mixins or i > 64: break scope.deferred.parsed[-1].pop() i += 1 scope.deferred.parsed[-1] = store if not mixins: # Fallback to blocks block = scope.blocks(ident.raw()) if not block: ident.parse(None) block = scope.blocks(ident.raw()) if block: scope.current = scope.real[-1] if scope.real else None res = block.copy_inner(scope) scope.current = None if mixins: for mixin in mixins: scope.current = scope.real[-1] if scope.real else None res = mixin.call(scope, args) if res: # Add variables to scope to support # closures [scope.add_variable(v) for v in mixin.vars] scope.deferred = ident break if res: store = [t for t in scope.deferred.parsed[ -1]] if scope.deferred else False tmp_res = [] for p in res: if p: if isinstance(p, Deferred): tmp_res.append(p.parse(scope, depth=depth + 1)) else: tmp_res.append(p.parse(scope)) res = tmp_res #res = [p.parse(scope, depth=depth+1) for p in res if p] while(any(t for t in res if isinstance(t, Deferred))): res = [p.parse(scope) for p in res if p] if store: scope.deferred.parsed[-1] = store if error and not res: raise SyntaxError('NameError `%s`' % ident.raw(True)) return res def copy(self): """ Returns self (used when Block objects are copy'd) returns: self """ return self