716 lines
22 KiB
Python
Raw Normal View History

2012-01-28 14:52:09 +00:00
"""
2012-02-19 20:38:19 +00:00
.. module:: parser
:synopsis: Lesscss parser.
2012-01-28 14:52:09 +00:00
http://www.dabeaz.com/ply/ply.html
http://www.w3.org/TR/CSS21/grammar.html#scanner
http://lesscss.org/#docs
Copyright (c)
See LICENSE for details.
2012-02-19 20:38:19 +00:00
.. moduleauthor:: Jóhann T. Maríusson <jtm@robot.is>
2012-01-28 14:52:09 +00:00
"""
import os
2012-02-25 18:28:05 +00:00
import copy
2012-01-28 14:52:09 +00:00
import ply.yacc
from . import lexer
from . import utility
2012-02-12 11:50:57 +00:00
from .scope import Scope
2012-03-10 16:27:14 +00:00
from .color import Color
2012-01-28 14:52:09 +00:00
from lesscpy.plib import *
2012-03-18 10:08:36 +00:00
2012-01-28 14:52:09 +00:00
class LessParser(object):
precedence = (
('left', '+', '-'),
('left', '*', '/'),
)
def __init__(self,
lex_optimize=True,
yacc_optimize=True,
2012-02-19 20:38:19 +00:00
tabfile='yacctab',
2012-01-28 14:52:09 +00:00
yacc_debug=False,
scope=None,
outputdir='/tmp',
2012-01-30 12:56:33 +00:00
importlvl=0,
verbose=False):
2012-01-28 14:52:09 +00:00
""" Parser object
2012-02-19 20:38:19 +00:00
Kwargs:
lex_optimize (bool): Optimize lexer
yacc_optimize (bool): Optimize parser
tabfile (str): Yacc tab filename
yacc_debug (bool): yacc debug mode
scope (Scope): Inherited scope
outputdir (str): Output (debugging)
importlvl (int): Import depth
verbose (bool): Verbose mode
2012-01-28 14:52:09 +00:00
"""
2012-01-30 12:56:33 +00:00
self.verbose = verbose
2012-01-28 14:52:09 +00:00
self.importlvl = importlvl
self.lex = lexer.LessLexer()
2012-02-19 20:38:19 +00:00
if not tabfile:
tabfile = 'yacctab'
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
self.ignored = ('css_comment', 'less_comment',
2012-03-16 15:08:45 +00:00
'css_vendor_hack', 'css_keyframes')
2012-01-28 14:52:09 +00:00
self.tokens = [t for t in self.lex.tokens
if t not in self.ignored]
self.parser = ply.yacc.yacc(
module=self,
2012-02-19 20:38:19 +00:00
start='tunit',
2012-01-28 14:52:09 +00:00
debug=yacc_debug,
optimize=yacc_optimize,
2012-02-19 20:38:19 +00:00
tabmodule=tabfile,
2012-01-28 14:52:09 +00:00
outputdir=outputdir
)
2012-02-12 11:50:57 +00:00
self.scope = scope if scope else Scope()
2012-01-28 14:52:09 +00:00
self.stash = {}
self.result = None
self.target = None
def parse(self, filename='', debuglevel=0):
""" Parse file.
@param string: Filename
@param int: Debuglevel
"""
2012-02-26 13:29:22 +00:00
if self.verbose: print('Compiling target: %s' % filename)
2012-02-12 11:50:57 +00:00
self.scope.push()
2012-01-28 14:52:09 +00:00
self.target = filename
self.result = self.parser.parse(filename, lexer=self.lex, debug=debuglevel)
def scopemap(self):
""" Output scopemap.
"""
2012-03-18 10:08:36 +00:00
utility.debug_print(self.result)
2012-02-19 20:38:19 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
def p_tunit(self, p):
""" tunit : unit_list
2012-01-28 14:52:09 +00:00
"""
2012-03-18 19:05:53 +00:00
p[0] = [u for u in p[1] if u]
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_unit_list(self, p):
""" unit_list : unit_list unit
| unit
2012-01-28 14:52:09 +00:00
"""
2012-03-18 19:05:53 +00:00
if type(p[1]) is list:
if len(p) >= 3:
if type(p[2]) is list:
p[1].extend(p[2])
else:
p[1].append(p[2])
2012-02-25 17:08:08 +00:00
else:
p[1] = [p[1]]
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_unit(self, p):
""" unit : statement
| variable_decl
| block_decl
| mixin_decl
2012-03-18 18:56:23 +00:00
| call_mixin
2012-01-28 14:52:09 +00:00
"""
2012-02-25 17:08:08 +00:00
p[0] = p[1]
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
2012-01-28 14:52:09 +00:00
def p_statement_aux(self, p):
2012-02-19 20:38:19 +00:00
""" statement : css_charset t_ws css_string ';'
| css_namespace t_ws css_string ';'
2012-01-28 14:52:09 +00:00
"""
2012-02-26 16:36:13 +00:00
p[0] = Statement(list(p)[1:], p.lineno(1))
2012-01-28 14:52:09 +00:00
p[0].parse(None)
def p_statement_namespace(self, p):
2012-02-19 20:38:19 +00:00
""" statement : css_namespace t_ws word css_string ';'
2012-01-28 14:52:09 +00:00
"""
2012-02-26 16:36:13 +00:00
p[0] = Statement(list(p)[1:], p.lineno(1))
2012-01-28 14:52:09 +00:00
p[0].parse(None)
def p_statement_import(self, p):
2012-02-19 20:38:19 +00:00
""" statement : css_import t_ws css_string ';'
2012-02-26 13:20:35 +00:00
| css_import t_ws css_string dom ';'
2012-01-28 14:52:09 +00:00
"""
if self.importlvl > 8:
raise ImportError('Recrusive import level too deep > 8 (circular import ?)')
2012-02-19 20:38:19 +00:00
ipath = utility.destring(p[3])
2012-01-28 14:52:09 +00:00
fn, fe = os.path.splitext(ipath)
if not fe or fe.lower() == '.less':
try:
cpath = os.path.dirname(os.path.abspath(self.target))
if not fe: ipath += '.less'
filename = "%s%s%s" % (cpath, os.sep, ipath)
if os.path.exists(filename):
2012-03-18 19:11:12 +00:00
recurse = LessParser(importlvl=self.importlvl+1,
verbose=self.verbose, scope=self.scope)
2012-01-28 14:52:09 +00:00
recurse.parse(filename=filename, debuglevel=0)
else:
err = "Cannot import '%s', file not found" % filename
2012-03-13 20:26:35 +00:00
self.handle_error(err, p.lineno(1), 'W')
2012-01-28 14:52:09 +00:00
p[0] = None
except ImportError as e:
self.handle_error(e, p)
else:
2012-02-26 16:36:13 +00:00
p[0] = Statement(list(p)[1:], p.lineno(1))
2012-01-28 14:52:09 +00:00
p[0].parse(None)
2012-02-19 20:38:19 +00:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2012-02-19 20:38:19 +00:00
#
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_block(self, p):
""" block_decl : block_open declaration_list brace_close
2012-01-28 14:52:09 +00:00
"""
try:
2012-02-26 15:50:07 +00:00
block = Block(list(p)[1:-1], p.lineno(3))
2012-03-18 10:08:36 +00:00
if not self.scope.in_mixin:
block.parse(self.scope)
2012-01-28 14:52:09 +00:00
p[0] = block
except SyntaxError as e:
2012-03-06 20:23:27 +00:00
self.handle_error(e, p.lineno(3))
2012-01-28 14:52:09 +00:00
p[0] = None
2012-02-26 15:50:07 +00:00
self.scope.pop()
2012-03-01 16:23:22 +00:00
self.scope.add_block(block)
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_block_replace(self, p):
""" block_decl : identifier ';'
2012-01-28 14:52:09 +00:00
"""
2012-02-25 18:28:05 +00:00
m = p[1].parse(None)
2012-03-01 16:23:22 +00:00
block = self.scope.blocks(m.raw())
2012-02-25 18:28:05 +00:00
if block:
2012-03-02 20:15:18 +00:00
p[0] = block.copy(self.scope)
2012-02-25 18:28:05 +00:00
else:
2012-03-18 14:21:58 +00:00
# fallback to mixin. Allow calls to mixins without parens
2012-03-03 19:58:56 +00:00
mixin = self.scope.mixins(m.raw())
if mixin:
try:
p[0] = mixin.call(self.scope)
except SyntaxError as e:
self.handle_error(e, p.lineno(2))
else:
2012-03-18 13:12:21 +00:00
self.handle_error('Call unknown block `%s`' % m.raw(True), p.lineno(2))
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_block_open(self, p):
""" block_open : identifier brace_open
2012-01-28 14:52:09 +00:00
"""
2012-02-28 21:26:08 +00:00
p[1].parse(self.scope)
2012-02-28 20:24:54 +00:00
p[0] = p[1]
2012-03-01 15:35:56 +00:00
self.scope.current = p[1]
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_font_face_open(self, p):
""" block_open : css_font_face t_ws brace_open
2012-01-28 14:52:09 +00:00
"""
2012-03-16 15:08:45 +00:00
p[0] = Identifier([p[1], p[2]]).parse(self.scope)
2012-02-25 18:28:05 +00:00
2012-02-19 20:38:19 +00:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2012-02-19 20:38:19 +00:00
#
def p_mixin(self, p):
""" mixin_decl : open_mixin declaration_list brace_close
2012-01-28 14:52:09 +00:00
"""
2012-03-03 15:16:29 +00:00
self.scope.add_mixin(Mixin(list(p)[1:], p.lineno(3)).parse(self.scope))
2012-02-26 15:50:07 +00:00
self.scope.pop()
2012-03-18 10:08:36 +00:00
self.scope.in_mixin = False
2012-03-03 15:16:29 +00:00
p[0] = None
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_open_mixin(self, p):
2012-03-18 13:21:47 +00:00
""" open_mixin : identifier t_popen mixin_args t_pclose brace_open
2012-01-28 14:52:09 +00:00
"""
2012-03-18 13:21:47 +00:00
p[1].parse(self.scope)
p[0] = [p[1], p[3]]
2012-03-18 10:08:36 +00:00
self.scope.in_mixin = True
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_call_mixin(self, p):
2012-03-18 13:21:47 +00:00
""" call_mixin : identifier t_popen mixin_args t_pclose ';'
2012-01-28 14:52:09 +00:00
"""
2012-03-18 13:21:47 +00:00
p[1].parse(None)
mixin = self.scope.mixins(p[1].raw())
2012-03-03 15:16:29 +00:00
if mixin:
2012-03-03 19:58:56 +00:00
try:
2012-03-18 10:08:36 +00:00
if self.scope.in_mixin:
p[0] = Deferred(mixin, p[3])
else:
p[0] = mixin.call(self.scope, p[3])
2012-03-03 19:58:56 +00:00
except SyntaxError as e:
self.handle_error(e, p.lineno(2))
2012-03-18 14:21:58 +00:00
elif not p[3]:
# fallback to block. Allow calls of name() to blocks
block = self.scope.blocks(p[1].raw())
if block:
p[0] = block.copy(self.scope)
2012-03-03 15:16:29 +00:00
else:
2012-03-18 14:21:58 +00:00
if self.scope.in_mixin:
p[0] = Deferred(p[1], p[3])
else:
self.handle_error('Call unknown mixin `%s`' % p[1].raw(True), p.lineno(2))
2012-03-13 20:26:35 +00:00
def p_mixin_args_arguments(self, p):
""" mixin_args : less_arguments
"""
p[0] = [p[1]]
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_mixin_args_aux(self, p):
""" mixin_args : mixin_args ',' argument
| mixin_args ',' mixin_kwarg
2012-03-13 20:26:35 +00:00
| mixin_args argument
| mixin_args mixin_kwarg
2012-01-28 14:52:09 +00:00
"""
2012-03-13 20:26:35 +00:00
p[1].extend(list(p)[2:])
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_mixin_args(self, p):
""" mixin_args : argument
| mixin_kwarg
2012-01-28 14:52:09 +00:00
"""
p[0] = [p[1]]
2012-03-03 15:16:29 +00:00
def p_mixin_args_empty(self, p):
""" mixin_args : empty
"""
p[0] = None
2012-02-19 20:38:19 +00:00
def p_mixin_kwarg(self, p):
""" mixin_kwarg : variable ':' argument
2012-01-28 14:52:09 +00:00
"""
2012-03-03 15:16:29 +00:00
p[0] = Variable(list(p)[1:], p.lineno(2))
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2012-02-19 20:38:19 +00:00
#
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_declaration_list(self, p):
""" declaration_list : declaration_list declaration
| declaration
| empty
2012-01-28 14:52:09 +00:00
"""
2012-02-19 20:38:19 +00:00
if len(p) > 2:
p[1].extend(p[2])
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_declaration(self, p):
""" declaration : variable_decl
| property_decl
| block_decl
| mixin_decl
| call_mixin
2012-01-28 14:52:09 +00:00
"""
2012-02-28 20:24:54 +00:00
p[0] = p[1] if type(p[1]) is list else [p[1]]
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
2012-01-28 14:52:09 +00:00
def p_variable_decl(self, p):
2012-02-19 20:38:19 +00:00
""" variable_decl : variable ':' style_list ';'
2012-01-28 14:52:09 +00:00
"""
try:
2012-02-26 15:50:07 +00:00
v = Variable(list(p)[1:], p.lineno(4))
2012-02-25 17:08:08 +00:00
v.parse(self.scope)
2012-03-16 15:39:03 +00:00
self.scope.add_variable(v)
2012-01-28 14:52:09 +00:00
except SyntaxError as e:
2012-03-18 10:08:36 +00:00
self.handle_error(e, p.lineno(2))
2012-01-28 14:52:09 +00:00
p[0] = None
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
def p_property_decl(self, p):
2012-02-19 20:38:19 +00:00
""" property_decl : prop_open style_list ';'
2012-02-26 10:59:21 +00:00
| prop_open style_list css_important ';'
2012-02-19 20:38:19 +00:00
| prop_open empty ';'
2012-01-28 14:52:09 +00:00
"""
2012-02-26 15:50:07 +00:00
l = len(p)
p[0] = Property(list(p)[1:-1], p.lineno(l-1))
2012-01-28 14:52:09 +00:00
2012-03-06 20:23:27 +00:00
def p_property_decl_arguments(self, p):
""" property_decl : prop_open less_arguments ';'
"""
p[0] = Property([p[1], [p[2]]], p.lineno(3))
2012-02-26 13:20:35 +00:00
def p_prop_open_ie_hack(self, p):
2012-02-26 15:50:07 +00:00
""" prop_open : '*' prop_open
2012-02-26 13:20:35 +00:00
"""
p[0] = (p[1][0], p[2][0])
2012-02-19 20:38:19 +00:00
def p_prop_open(self, p):
""" prop_open : property ':'
| vendor_property ':'
| word ':'
2012-01-28 14:52:09 +00:00
"""
2012-02-26 13:20:35 +00:00
p[0] = (p[1][0], '')
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
2012-02-19 20:38:19 +00:00
def p_style_list_aux(self, p):
""" style_list : style_list style
| style_list ',' style
2012-03-13 20:26:35 +00:00
| style_list t_ws style
2012-02-19 20:38:19 +00:00
"""
p[1].extend(list(p)[2:])
p[0] = p[1]
2012-01-28 14:52:09 +00:00
def p_style_list(self, p):
2012-02-19 20:38:19 +00:00
""" style_list : style
"""
p[0] = [p[1]]
def p_style(self, p):
""" style : expression
| css_string
| word
| property
| vendor_property
| istring
| fcall
2012-01-28 14:52:09 +00:00
"""
p[0] = p[1]
2012-02-19 20:38:19 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2012-02-27 18:48:20 +00:00
#
2012-02-19 20:38:19 +00:00
def p_identifier(self, p):
""" identifier : identifier_list
2012-03-16 15:08:45 +00:00
| page
| page filter
2012-01-28 14:52:09 +00:00
"""
2012-02-26 15:50:07 +00:00
p[0] = Identifier(p[1], 0)
2012-02-19 20:38:19 +00:00
def p_identifier_list_aux(self, p):
""" identifier_list : identifier_list ',' identifier_group
"""
p[1].extend([p[2]])
p[1].extend(p[3])
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_identifier_list(self, p):
""" identifier_list : identifier_group
2012-01-28 14:52:09 +00:00
"""
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_identifier_group_op(self, p):
""" identifier_group : identifier_group child_selector ident_parts
2012-02-26 15:50:07 +00:00
| identifier_group '+' ident_parts
2012-02-26 10:59:21 +00:00
| identifier_group general_sibling_selector ident_parts
2012-03-15 18:56:51 +00:00
| identifier_group '*'
2012-01-28 14:52:09 +00:00
"""
p[1].extend([p[2]])
2012-03-15 18:56:51 +00:00
if len(p) > 3: p[1].extend(p[3])
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_identifier_group(self, p):
""" identifier_group : ident_parts
2012-01-28 14:52:09 +00:00
"""
2012-02-19 20:38:19 +00:00
p[0] = p[1]
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_ident_parts_aux(self, p):
""" ident_parts : ident_parts ident_part
| ident_parts filter_group
2012-01-28 14:52:09 +00:00
"""
2012-02-19 20:38:19 +00:00
if type(p[2]) is list:
p[1].extend(p[2])
else: p[1].append(p[2])
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_ident_parts(self, p):
""" ident_parts : ident_part
| selector
| filter_group
2012-01-28 14:52:09 +00:00
"""
2012-02-19 20:38:19 +00:00
if type(p[1]) is not list:
p[1] = [p[1]]
p[0] = p[1]
2012-01-28 14:52:09 +00:00
2012-02-27 18:48:20 +00:00
def p_ident_media(self, p):
""" ident_parts : css_media t_ws
"""
p[0] = list(p)[1:]
2012-02-19 20:38:19 +00:00
def p_selector(self, p):
2012-02-26 17:17:05 +00:00
""" selector : '*'
2012-02-26 15:50:07 +00:00
| '+'
2012-02-26 10:59:21 +00:00
| child_selector
| general_sibling_selector
2012-01-28 14:52:09 +00:00
"""
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_ident_part(self, p):
""" ident_part : class
| id
| dom
2012-02-26 17:17:05 +00:00
| combinator
2012-02-27 18:48:20 +00:00
| color
2012-01-28 14:52:09 +00:00
"""
2012-02-19 20:38:19 +00:00
p[0] = p[1]
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
2012-02-19 20:38:19 +00:00
def p_filter_group_aux(self, p):
""" filter_group : filter_group filter
2012-01-28 14:52:09 +00:00
"""
2012-02-19 20:38:19 +00:00
p[1].extend(p[2])
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_filter_group(self, p):
""" filter_group : filter
2012-01-28 14:52:09 +00:00
"""
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_filter(self, p):
""" filter : css_filter
| ':' word
| ':' vendor_property
2012-03-16 15:08:45 +00:00
| ':' vendor_property t_ws
| ':' css_property
| ':' css_property t_ws
2012-02-19 20:38:19 +00:00
| ':' css_filter
| ':' ':' word
| ':' ':' vendor_property
"""
p[0] = list(p)[1:]
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2012-02-19 20:38:19 +00:00
#
2012-01-28 14:52:09 +00:00
def p_fcall(self, p):
2012-02-19 20:38:19 +00:00
""" fcall : word t_popen argument_list t_pclose
| property t_popen argument_list t_pclose
| vendor_property t_popen argument_list t_pclose
2012-02-12 10:11:04 +00:00
| less_open_format argument_list t_pclose
2012-02-26 13:20:35 +00:00
| '~' istring
| '~' css_string
2012-01-28 14:52:09 +00:00
"""
2012-02-26 15:50:07 +00:00
p[0] = Call(list(p)[1:], 0)
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
2012-03-15 19:20:04 +00:00
def p_argument_list_empty(self, p):
""" argument_list : empty
"""
p[0] = ''
2012-01-28 14:52:09 +00:00
def p_argument_list_aux(self, p):
2012-02-19 20:38:19 +00:00
""" argument_list : argument_list argument
| argument_list ',' argument
2012-01-28 14:52:09 +00:00
"""
2012-02-19 20:38:19 +00:00
p[1].extend(list(p)[2:])
2012-01-28 14:52:09 +00:00
p[0] = p[1]
def p_argument_list(self, p):
2012-03-13 20:26:35 +00:00
""" argument_list : argument
2012-01-28 14:52:09 +00:00
"""
p[0] = [p[1]]
def p_argument(self, p):
""" argument : expression
| css_string
| istring
2012-02-19 20:38:19 +00:00
| word
| id
2012-01-28 14:52:09 +00:00
| css_uri
| '='
2012-02-19 20:38:19 +00:00
| fcall
2012-01-28 14:52:09 +00:00
"""
p[0] = p[1]
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
2012-02-19 20:38:19 +00:00
def p_expression_aux(self, p):
2012-02-26 15:50:07 +00:00
""" expression : expression '+' expression
| expression '-' expression
| expression '/' expression
| expression '*' expression
| word '/' expression
2012-02-19 20:38:19 +00:00
"""
2012-02-26 15:50:07 +00:00
p[0] = Expression(list(p)[1:], 0)
2012-02-19 20:38:19 +00:00
def p_expression_p_neg(self, p):
2012-02-26 15:50:07 +00:00
""" expression : '-' t_popen expression t_pclose
2012-02-19 20:38:19 +00:00
"""
p[0] = [p[1], p[3]]
def p_expression_p(self, p):
""" expression : t_popen expression t_pclose
"""
p[0] = p[2]
def p_expression(self, p):
""" expression : factor
"""
p[0] = p[1]
def p_factor(self, p):
""" factor : color
| number
| variable
| css_dom
"""
p[0] = p[1]
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
2012-01-28 14:52:09 +00:00
def p_interpolated_str(self, p):
2012-02-19 20:38:19 +00:00
""" istring : less_string
2012-01-28 14:52:09 +00:00
"""
2012-03-03 09:58:47 +00:00
p[0] = String(p[1], p.lineno(1))
2012-01-28 14:52:09 +00:00
def p_variable_neg(self, p):
2012-02-26 15:50:07 +00:00
""" variable : '-' variable
2012-01-28 14:52:09 +00:00
"""
p[0] = '-' + p[2]
def p_variable_strange(self, p):
2012-02-19 20:38:19 +00:00
""" variable : t_popen variable t_pclose
2012-01-28 14:52:09 +00:00
"""
p[0] = p[2]
def p_variable(self, p):
2012-02-19 20:38:19 +00:00
""" variable : less_variable
| less_variable t_ws
2012-01-28 14:52:09 +00:00
"""
p[0] = p[1]
2012-02-19 20:38:19 +00:00
2012-01-28 14:52:09 +00:00
def p_color(self, p):
2012-03-15 18:52:26 +00:00
""" color : css_color
| css_color t_ws
2012-01-28 14:52:09 +00:00
"""
2012-03-13 21:12:09 +00:00
try:
p[0] = Color().fmt(p[1])
2012-03-15 18:52:26 +00:00
if len(p) > 2: p[0] = [p[0], p[2]]
2012-03-13 21:12:09 +00:00
except ValueError:
self.handle_error('Illegal color value `%s`' % p[1], p.lineno(1), 'W')
p[0] = p[1]
2012-02-19 20:38:19 +00:00
2012-01-28 14:52:09 +00:00
def p_number(self, p):
2012-02-19 20:38:19 +00:00
""" number : css_number
| css_number t_ws
2012-01-28 14:52:09 +00:00
"""
2012-02-19 20:38:19 +00:00
p[0] = tuple(list(p)[1:])
2012-01-28 14:52:09 +00:00
2012-02-19 20:38:19 +00:00
def p_dom(self, p):
""" dom : css_dom
| css_dom t_ws
"""
p[0] = tuple(list(p)[1:])
def p_word(self, p):
""" word : css_ident
| css_ident t_ws
"""
p[0] = tuple(list(p)[1:])
def p_class(self, p):
""" class : css_class
| css_class t_ws
"""
p[0] = tuple(list(p)[1:])
def p_id(self, p):
""" id : css_id
| css_id t_ws
"""
p[0] = tuple(list(p)[1:])
def p_property(self, p):
""" property : css_property
| css_property t_ws
"""
p[0] = tuple(list(p)[1:])
2012-03-16 15:08:45 +00:00
def p_page(self, p):
""" page : css_page
| css_page t_ws
"""
p[0] = tuple(list(p)[1:])
2012-02-19 20:38:19 +00:00
def p_vendor_property(self, p):
""" vendor_property : css_vendor_property
| css_vendor_property t_ws
"""
p[0] = tuple(list(p)[1:])
def p_combinator(self, p):
""" combinator : '&' t_ws
| '&'
"""
p[0] = tuple(list(p)[1:])
2012-02-26 10:59:21 +00:00
2012-02-19 20:38:19 +00:00
def p_child_selector(self, p):
""" child_selector : '>' t_ws
| '>'
"""
p[0] = tuple(list(p)[1:])
2012-01-28 14:52:09 +00:00
2012-02-26 10:59:21 +00:00
def p_general_sibling_selector(self, p):
""" general_sibling_selector : '~' t_ws
| '~'
"""
p[0] = tuple(list(p)[1:])
2012-01-28 14:52:09 +00:00
def p_scope_open(self, p):
2012-02-25 11:09:49 +00:00
""" brace_open : '{'
2012-01-28 14:52:09 +00:00
"""
2012-02-12 11:50:57 +00:00
self.scope.push()
2012-01-28 14:52:09 +00:00
p[0] = p[1]
def p_scope_close(self, p):
2012-02-25 11:09:49 +00:00
""" brace_close : '}'
2012-01-28 14:52:09 +00:00
"""
p[0] = p[1]
2012-02-19 20:38:19 +00:00
def p_empty(self, p):
2012-02-25 11:09:49 +00:00
'empty :'
2012-02-19 20:38:19 +00:00
pass
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
def p_error(self, t):
""" Internal error handler
@param Lex token: Error token
"""
2012-01-30 12:56:33 +00:00
if t and self.verbose:
2012-03-15 20:05:22 +00:00
print("\x1b[31mE: %s line: %d, Syntax Error, token: `%s`, `%s`\x1b[0m"
2012-01-30 13:54:31 +00:00
% (self.target, t.lineno, t.type, t.value))
2012-01-28 14:52:09 +00:00
while True:
t = self.lex.token()
if not t or t.value == '}':
if len(self.scope) > 1:
self.scope.pop()
break
self.parser.restart()
return t
2012-03-03 15:16:29 +00:00
def handle_error(self, e, line, t='E'):
2012-01-28 14:52:09 +00:00
""" Custom error handler
@param Exception: Exception
@param Parser token: Parser token
@param string: Error level
"""
2012-03-18 10:08:36 +00:00
# print(e.trace())
2012-01-30 12:56:33 +00:00
if self.verbose:
2012-03-15 20:05:22 +00:00
color = '\x1b[31m' if t == 'E' else '\x1b[33m'
print("%s%s: line: %d: %s\n" % (color, t, line, e), end='\x1b[0m')
2012-02-11 18:02:08 +00:00