207 lines
5.9 KiB
Python
207 lines
5.9 KiB
Python
"""
|
|
.. module:: lesscpy.lessc.scope
|
|
:synopsis: Scope class.
|
|
|
|
|
|
Copyright (c)
|
|
See LICENSE for details.
|
|
.. moduleauthor:: Johann T. Mariusson <jtm@robot.is>
|
|
"""
|
|
from . import utility
|
|
|
|
|
|
class Scope(list):
|
|
|
|
""" Scope class. A stack implementation.
|
|
"""
|
|
|
|
def __init__(self, init=False):
|
|
"""Scope
|
|
Args:
|
|
init (bool): Initiate scope
|
|
"""
|
|
super(Scope, self).__init__()
|
|
self._mixins = {}
|
|
if init:
|
|
self.push()
|
|
self.deferred = False
|
|
self.real = []
|
|
|
|
def push(self):
|
|
"""Push level on scope
|
|
"""
|
|
self.append({
|
|
'__variables__': {},
|
|
'__blocks__': [],
|
|
'__names__': [],
|
|
'__current__': None
|
|
})
|
|
|
|
@property
|
|
def current(self):
|
|
return self[-1]['__current__']
|
|
|
|
@current.setter
|
|
def current(self, value):
|
|
self[-1]['__current__'] = value
|
|
|
|
@property
|
|
def scopename(self):
|
|
"""Current scope name as list
|
|
Returns:
|
|
list
|
|
"""
|
|
return [r['__current__']
|
|
for r in self
|
|
if r['__current__']]
|
|
|
|
def add_block(self, block):
|
|
"""Add block element to scope
|
|
Args:
|
|
block (Block): Block object
|
|
"""
|
|
self[-1]['__blocks__'].append(block)
|
|
self[-1]['__names__'].append(block.raw())
|
|
|
|
def remove_block(self, block, index="-1"):
|
|
"""Remove block element from scope
|
|
Args:
|
|
block (Block): Block object
|
|
"""
|
|
self[index]["__blocks__"].remove(block)
|
|
self[index]["__names__"].remove(block.raw())
|
|
|
|
def add_mixin(self, mixin):
|
|
"""Add mixin to scope
|
|
Args:
|
|
mixin (Mixin): Mixin object
|
|
"""
|
|
raw = mixin.tokens[0][0].raw()
|
|
if raw in self._mixins:
|
|
self._mixins[raw].append(mixin)
|
|
else:
|
|
self._mixins[raw] = [mixin]
|
|
|
|
def add_variable(self, variable):
|
|
"""Add variable to scope
|
|
Args:
|
|
variable (Variable): Variable object
|
|
"""
|
|
self[-1]['__variables__'][variable.name] = variable
|
|
|
|
def variables(self, name):
|
|
"""Search for variable by name. Searches scope top down
|
|
Args:
|
|
name (string): Search term
|
|
Returns:
|
|
Variable object OR False
|
|
"""
|
|
if isinstance(name, tuple):
|
|
name = name[0]
|
|
if name.startswith('@{'):
|
|
name = '@' + name[2:-1]
|
|
i = len(self)
|
|
while i >= 0:
|
|
i -= 1
|
|
if name in self[i]['__variables__']:
|
|
return self[i]['__variables__'][name]
|
|
return False
|
|
|
|
def mixins(self, name):
|
|
""" Search mixins for name.
|
|
Allow '>' to be ignored. '.a .b()' == '.a > .b()'
|
|
Args:
|
|
name (string): Search term
|
|
Returns:
|
|
Mixin object list OR False
|
|
"""
|
|
m = self._smixins(name)
|
|
if m:
|
|
return m
|
|
return self._smixins(name.replace('?>?', ' '))
|
|
|
|
def _smixins(self, name):
|
|
"""Inner wrapper to search for mixins by name.
|
|
"""
|
|
return (self._mixins[name]
|
|
if name in self._mixins
|
|
else False)
|
|
|
|
def blocks(self, name):
|
|
"""
|
|
Search for defined blocks recursively.
|
|
Allow '>' to be ignored. '.a .b' == '.a > .b'
|
|
Args:
|
|
name (string): Search term
|
|
Returns:
|
|
Block object OR False
|
|
"""
|
|
b = self._blocks(name)
|
|
if b:
|
|
return b
|
|
return self._blocks(name.replace('?>?', ' '))
|
|
|
|
def _blocks(self, name):
|
|
"""Inner wrapper to search for blocks by name.
|
|
"""
|
|
i = len(self)
|
|
while i >= 0:
|
|
i -= 1
|
|
if name in self[i]['__names__']:
|
|
for b in self[i]['__blocks__']:
|
|
r = b.raw()
|
|
if r and r == name:
|
|
return b
|
|
else:
|
|
for b in self[i]['__blocks__']:
|
|
r = b.raw()
|
|
if r and name.startswith(r):
|
|
b = utility.blocksearch(b, name)
|
|
if b:
|
|
return b
|
|
return False
|
|
|
|
def update(self, scope, at=0):
|
|
"""Update scope. Add another scope to this one.
|
|
Args:
|
|
scope (Scope): Scope object
|
|
Kwargs:
|
|
at (int): Level to update
|
|
"""
|
|
if hasattr(scope, '_mixins') and not at:
|
|
self._mixins.update(scope._mixins)
|
|
self[at]['__variables__'].update(scope[at]['__variables__'])
|
|
self[at]['__blocks__'].extend(scope[at]['__blocks__'])
|
|
self[at]['__names__'].extend(scope[at]['__names__'])
|
|
|
|
def swap(self, name):
|
|
""" Swap variable name for variable value
|
|
Args:
|
|
name (str): Variable name
|
|
Returns:
|
|
Variable value (Mixed)
|
|
"""
|
|
if name.startswith('@@'):
|
|
var = self.variables(name[1:])
|
|
if var is False:
|
|
raise SyntaxError('Unknown variable %s' % name)
|
|
name = '@' + utility.destring(var.value[0])
|
|
var = self.variables(name)
|
|
if var is False:
|
|
raise SyntaxError('Unknown variable %s' % name)
|
|
elif name.startswith('@{'):
|
|
var = self.variables('@' + name[2:-1])
|
|
if var is False:
|
|
raise SyntaxError('Unknown escaped variable %s' % name)
|
|
try:
|
|
if isinstance(var.value[0], basestring): # py3
|
|
var.value[0] = utility.destring(var.value[0])
|
|
except NameError:
|
|
if isinstance(var.value[0], str): # py2
|
|
var.value[0] = utility.destring(var.value[0])
|
|
else:
|
|
var = self.variables(name)
|
|
if var is False:
|
|
raise SyntaxError('Unknown variable %s' % name)
|
|
return var.value
|