232 lines
6.1 KiB
Python
232 lines
6.1 KiB
Python
# -*- coding: utf8 -*-
|
|
"""
|
|
.. module:: lesscpy.plib.call
|
|
:synopsis: Call parse node
|
|
|
|
Copyright (c)
|
|
See LICENSE for details.
|
|
.. moduleauthor:: Johann T. Mariusson <jtm@robot.is>
|
|
"""
|
|
import re
|
|
import math
|
|
try:
|
|
from urllib.parse import quote as urlquote
|
|
except ImportError:
|
|
from urllib import quote as urlquote
|
|
from .node import Node
|
|
import lesscpy.lessc.utility as utility
|
|
import lesscpy.lessc.color as Color
|
|
from lesscpy.lib.colors import lessColors
|
|
|
|
|
|
class Call(Node):
|
|
|
|
"""Call node. Node represents a function call.
|
|
All builtin none-color functions are in this node.
|
|
This node attempts calls on built-ins and lets non-builtins
|
|
through.
|
|
increment(3px) --> 4px
|
|
unknown(3px) --> unknown(3px)
|
|
"""
|
|
|
|
def parse(self, scope):
|
|
"""Parse Node within scope.
|
|
the functions ~( and e( map to self.escape
|
|
and %( maps to self.sformat
|
|
args:
|
|
scope (Scope): Current scope
|
|
"""
|
|
name = ''.join(self.tokens[0])
|
|
parsed = self.process(self.tokens[1:], scope)
|
|
|
|
if name == '%(':
|
|
name = 'sformat'
|
|
elif name in ('~', 'e'):
|
|
name = 'escape'
|
|
color = Color.Color()
|
|
args = [t for t in parsed
|
|
if not isinstance(t, str) or t not in '(),']
|
|
if hasattr(self, name):
|
|
try:
|
|
return getattr(self, name)(*args)
|
|
except ValueError:
|
|
pass
|
|
|
|
if hasattr(color, name):
|
|
try:
|
|
result = getattr(color, name)(*args)
|
|
try:
|
|
return result + ' '
|
|
except TypeError:
|
|
return result
|
|
except ValueError:
|
|
pass
|
|
return name + ''.join([p for p in parsed])
|
|
|
|
def escape(self, string, *args):
|
|
"""Less Escape.
|
|
args:
|
|
string (str): string to escape
|
|
returns:
|
|
str
|
|
"""
|
|
return utility.destring(string.strip('~'))
|
|
|
|
def sformat(self, string, *args):
|
|
""" String format.
|
|
args:
|
|
string (str): string to format
|
|
args (list): format options
|
|
returns:
|
|
str
|
|
"""
|
|
format = string
|
|
items = []
|
|
m = re.findall('(%[asdA])', format)
|
|
if m and not args:
|
|
raise SyntaxError('Not enough arguments...')
|
|
i = 0
|
|
for n in m:
|
|
v = {
|
|
'%A': urlquote,
|
|
'%s': utility.destring,
|
|
}.get(n, str)(args[i])
|
|
items.append(v)
|
|
i += 1
|
|
format = format.replace('%A', '%s')
|
|
format = format.replace('%d', '%s')
|
|
return format % tuple(items)
|
|
|
|
def isnumber(self, string, *args):
|
|
"""Is number
|
|
args:
|
|
string (str): match
|
|
returns:
|
|
bool
|
|
"""
|
|
try:
|
|
n, u = utility.analyze_number(string)
|
|
except SyntaxError:
|
|
return False
|
|
return True
|
|
|
|
def iscolor(self, string, *args):
|
|
"""Is color
|
|
args:
|
|
string (str): match
|
|
returns:
|
|
bool
|
|
"""
|
|
return (string in lessColors)
|
|
|
|
def isurl(self, string, *args):
|
|
"""Is url
|
|
args:
|
|
string (str): match
|
|
returns:
|
|
bool
|
|
"""
|
|
arg = utility.destring(string)
|
|
regex = re.compile(r'^(?:http|ftp)s?://' # http:// or https://
|
|
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+'
|
|
r'(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
|
|
# localhost...
|
|
r'localhost|'
|
|
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
|
|
# optional port
|
|
r'(?::\d+)?'
|
|
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
|
return regex.match(arg)
|
|
|
|
def isstring(self, string, *args):
|
|
"""Is string
|
|
args:
|
|
string (str): match
|
|
returns:
|
|
bool
|
|
"""
|
|
regex = re.compile(r'\'[^\']*\'|"[^"]*"')
|
|
return regex.match(string)
|
|
|
|
def iskeyword(self, string, *args):
|
|
"""Is less keyword
|
|
args:
|
|
string (str): match
|
|
returns:
|
|
bool
|
|
"""
|
|
return (string in ('when', 'and', 'not'))
|
|
|
|
def increment(self, value, *args):
|
|
""" Increment function
|
|
args:
|
|
value (str): target
|
|
returns:
|
|
str
|
|
"""
|
|
n, u = utility.analyze_number(value)
|
|
return utility.with_unit(n + 1, u)
|
|
|
|
def decrement(self, value, *args):
|
|
""" Decrement function
|
|
args:
|
|
value (str): target
|
|
returns:
|
|
str
|
|
"""
|
|
n, u = utility.analyze_number(value)
|
|
return utility.with_unit(n - 1, u)
|
|
|
|
def add(self, *args):
|
|
""" Add integers
|
|
args:
|
|
args (list): target
|
|
returns:
|
|
str
|
|
"""
|
|
if(len(args) <= 1):
|
|
return 0
|
|
return sum([int(v) for v in args])
|
|
|
|
def round(self, value, *args):
|
|
""" Round number
|
|
args:
|
|
value (str): target
|
|
returns:
|
|
str
|
|
"""
|
|
n, u = utility.analyze_number(value)
|
|
return utility.with_unit(int(utility.away_from_zero_round(float(n))), u)
|
|
|
|
def ceil(self, value, *args):
|
|
""" Ceil number
|
|
args:
|
|
value (str): target
|
|
returns:
|
|
str
|
|
"""
|
|
n, u = utility.analyze_number(value)
|
|
return utility.with_unit(int(math.ceil(n)), u)
|
|
|
|
def floor(self, value, *args):
|
|
""" Floor number
|
|
args:
|
|
value (str): target
|
|
returns:
|
|
str
|
|
"""
|
|
n, u = utility.analyze_number(value)
|
|
return utility.with_unit(int(math.floor(n)), u)
|
|
|
|
def percentage(self, value, *args):
|
|
""" Return percentage value
|
|
args:
|
|
value (str): target
|
|
returns:
|
|
str
|
|
"""
|
|
n, u = utility.analyze_number(value)
|
|
n = int(n * 100.0)
|
|
u = '%'
|
|
return utility.with_unit(n, u)
|