2012-04-03 13:36:08 +00:00
|
|
|
# -*- coding: utf8 -*-
|
2012-01-28 14:52:09 +00:00
|
|
|
"""
|
2012-04-03 13:36:08 +00:00
|
|
|
.. module:: lesscpy.plib.expression
|
|
|
|
:synopsis: Expression node.
|
2013-07-19 11:21:51 +02:00
|
|
|
|
2012-04-03 13:36:08 +00:00
|
|
|
Copyright (c)
|
|
|
|
See LICENSE for details.
|
2012-07-18 17:28:04 -04:00
|
|
|
.. moduleauthor:: Johann T. Mariusson <jtm@robot.is>
|
2012-01-28 14:52:09 +00:00
|
|
|
"""
|
2013-08-12 14:46:23 +02:00
|
|
|
|
|
|
|
import operator
|
|
|
|
|
2012-02-19 20:38:19 +00:00
|
|
|
from .node import Node
|
2012-02-25 17:08:08 +00:00
|
|
|
from lesscpy.lessc import utility
|
2012-02-25 17:34:23 +00:00
|
|
|
from lesscpy.lessc import color
|
2012-02-25 17:08:08 +00:00
|
|
|
|
2013-07-19 11:21:51 +02:00
|
|
|
|
2012-02-19 20:38:19 +00:00
|
|
|
class Expression(Node):
|
2013-07-19 11:21:51 +02:00
|
|
|
|
2012-04-03 13:36:08 +00:00
|
|
|
"""Expression node. Parses all expression except
|
|
|
|
color expressions, (handled in the color class)
|
|
|
|
"""
|
2013-07-19 11:21:51 +02:00
|
|
|
|
2012-02-25 17:08:08 +00:00
|
|
|
def parse(self, scope):
|
|
|
|
""" Parse Node
|
2012-04-03 13:36:08 +00:00
|
|
|
args:
|
|
|
|
scope (Scope): Scope object
|
|
|
|
raises:
|
|
|
|
SyntaxError
|
|
|
|
returns:
|
|
|
|
str
|
2012-02-25 17:08:08 +00:00
|
|
|
"""
|
|
|
|
assert(len(self.tokens) == 3)
|
2012-02-26 15:50:07 +00:00
|
|
|
expr = self.process(self.tokens, scope)
|
2012-02-25 17:08:08 +00:00
|
|
|
expr = [self.neg(t, scope) for t in expr]
|
2013-07-19 11:21:51 +02:00
|
|
|
A, O, B = [e[0]
|
|
|
|
if isinstance(e, tuple)
|
|
|
|
else e
|
2012-02-26 15:50:07 +00:00
|
|
|
for e in expr
|
2012-02-26 17:04:50 +00:00
|
|
|
if str(e).strip()]
|
2012-02-25 17:34:23 +00:00
|
|
|
try:
|
|
|
|
a, ua = utility.analyze_number(A, 'Illegal element in expression')
|
|
|
|
b, ub = utility.analyze_number(B, 'Illegal element in expression')
|
|
|
|
except SyntaxError:
|
|
|
|
return ' '.join([str(A), str(O), str(B)])
|
2012-02-25 17:08:08 +00:00
|
|
|
if(a is False or b is False):
|
2012-02-25 17:34:23 +00:00
|
|
|
return ' '.join([str(A), str(O), str(B)])
|
2012-02-25 17:08:08 +00:00
|
|
|
if ua == 'color' or ub == 'color':
|
2012-03-10 16:27:14 +00:00
|
|
|
return color.Color().process((A, O, B))
|
2013-12-18 15:24:54 +01:00
|
|
|
if a == 0 and O == '/':
|
|
|
|
# NOTE(saschpe): The ugliest but valid CSS since sliced bread: 'font: 0/1 a;'
|
|
|
|
return ''.join([str(A), str(O), str(B), ' '])
|
2012-02-25 17:08:08 +00:00
|
|
|
out = self.operate(a, b, O)
|
2013-07-19 11:21:51 +02:00
|
|
|
if isinstance(out, bool):
|
2012-04-04 12:33:49 +00:00
|
|
|
return out
|
2012-02-25 17:08:08 +00:00
|
|
|
return self.with_units(out, ua, ub)
|
2013-07-19 11:21:51 +02:00
|
|
|
|
2012-04-03 13:36:08 +00:00
|
|
|
def neg(self, value, scope):
|
|
|
|
"""Apply negativity.
|
|
|
|
args:
|
|
|
|
value (mixed): test value
|
|
|
|
scope (Scope): Current scope
|
|
|
|
raises:
|
|
|
|
SyntaxError
|
|
|
|
returns:
|
|
|
|
str
|
2012-02-25 17:08:08 +00:00
|
|
|
"""
|
2013-07-19 11:21:51 +02:00
|
|
|
if value and isinstance(value, list) and value[0] == '-':
|
2012-04-03 13:36:08 +00:00
|
|
|
val = value[1]
|
|
|
|
if len(value) > 1 and hasattr(value[1], 'parse'):
|
|
|
|
val = value[1].parse(scope)
|
2013-07-19 11:21:51 +02:00
|
|
|
if isinstance(val, str):
|
2012-04-03 13:36:08 +00:00
|
|
|
return '-' + val
|
|
|
|
return -val
|
|
|
|
return value
|
2013-07-19 11:21:51 +02:00
|
|
|
|
2012-04-03 13:36:08 +00:00
|
|
|
def with_units(self, val, ua, ub):
|
2013-07-19 11:21:51 +02:00
|
|
|
"""Return value with unit.
|
2012-04-03 13:36:08 +00:00
|
|
|
args:
|
|
|
|
val (mixed): result
|
|
|
|
ua (str): 1st unit
|
|
|
|
ub (str): 2nd unit
|
|
|
|
raises:
|
|
|
|
SyntaxError
|
|
|
|
returns:
|
|
|
|
str
|
2012-02-25 17:08:08 +00:00
|
|
|
"""
|
2013-07-19 11:21:51 +02:00
|
|
|
if not val:
|
|
|
|
return str(val)
|
2012-02-25 17:34:23 +00:00
|
|
|
if ua or ub:
|
|
|
|
if ua and ub:
|
|
|
|
if ua == ub:
|
2012-04-03 13:36:08 +00:00
|
|
|
return str(val) + ua
|
2012-02-25 17:34:23 +00:00
|
|
|
else:
|
2013-07-19 11:21:51 +02:00
|
|
|
# Nodejs version does not seem to mind mismatched
|
2012-06-25 08:18:49 +00:00
|
|
|
# units within expressions. So we choose the first
|
|
|
|
# as they do
|
|
|
|
# raise SyntaxError("Error in expression %s != %s" % (ua, ub))
|
|
|
|
return str(val) + ua
|
2012-02-25 17:34:23 +00:00
|
|
|
elif ua:
|
2012-04-03 13:36:08 +00:00
|
|
|
return str(val) + ua
|
2012-02-25 17:34:23 +00:00
|
|
|
elif ub:
|
2012-04-03 13:36:08 +00:00
|
|
|
return str(val) + ub
|
2013-08-08 15:12:03 +02:00
|
|
|
return repr(val)
|
2013-07-19 11:21:51 +02:00
|
|
|
|
2012-04-03 13:36:08 +00:00
|
|
|
def operate(self, vala, valb, oper):
|
|
|
|
"""Perform operation
|
|
|
|
args:
|
|
|
|
vala (mixed): 1st value
|
|
|
|
valb (mixed): 2nd value
|
|
|
|
oper (str): operation
|
|
|
|
returns:
|
|
|
|
mixed
|
2012-02-25 17:08:08 +00:00
|
|
|
"""
|
|
|
|
operation = {
|
2013-08-12 14:46:23 +02:00
|
|
|
'+': operator.add,
|
|
|
|
'-': operator.sub,
|
|
|
|
'*': operator.mul,
|
|
|
|
'/': operator.truediv,
|
|
|
|
'=': operator.eq,
|
|
|
|
'>': operator.gt,
|
|
|
|
'<': operator.lt,
|
|
|
|
'>=': operator.ge,
|
2013-12-18 10:02:55 +01:00
|
|
|
'=<': operator.le,
|
2012-04-03 13:36:08 +00:00
|
|
|
}.get(oper)
|
2013-12-18 10:02:55 +01:00
|
|
|
if operation is None:
|
|
|
|
raise SyntaxError("Unknown operation %s" % oper)
|
2013-08-12 14:46:23 +02:00
|
|
|
ret = operation(vala, valb)
|
|
|
|
if oper in '+-*/' and int(ret) == ret:
|
|
|
|
ret = int(ret)
|
2012-07-19 09:31:18 +00:00
|
|
|
return ret
|
2013-07-19 11:21:51 +02:00
|
|
|
|
2012-02-26 11:19:10 +00:00
|
|
|
def expression(self):
|
2012-04-03 13:36:08 +00:00
|
|
|
"""Return str representation of expression
|
|
|
|
returns:
|
|
|
|
str
|
2012-02-26 11:19:10 +00:00
|
|
|
"""
|
|
|
|
return utility.flatten(self.tokens)
|