886 lines
26 KiB
Python
Raw Normal View History

2012-03-30 07:53:51 +00:00
# -*- coding: utf8 -*-
2012-01-28 14:52:09 +00:00
"""
2012-03-30 16:12:24 +00:00
.. module:: lesscpy.lessc.parser
2012-02-19 20:38:19 +00:00
:synopsis: Lesscss parser.
2013-07-19 11:21:51 +02:00
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
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +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-07-19 11:53:00 +02:00
from __future__ import print_function
2012-01-28 14:52:09 +00:00
import os
2012-04-17 12:26:19 +00:00
import sys
2012-01-28 14:52:09 +00:00
import ply.yacc
2013-07-19 11:53:00 +02:00
2012-01-28 14:52:09 +00:00
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
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
class LessParser(object):
precedence = (
2013-07-19 11:21:51 +02:00
('left', '+', '-'),
('left', '*', '/'),
2012-01-28 14:52:09 +00:00
)
2013-07-19 11:21:51 +02:00
def __init__(self,
lex_optimize=True,
yacc_optimize=True,
tabfile='yacctab',
yacc_debug=False,
scope=None,
outputdir='/tmp',
importlvl=0,
verbose=False
):
2012-01-28 14:52:09 +00:00
""" Parser object
2013-07-19 11:21:51 +02:00
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
"""
2013-07-19 11:21:51 +02:00
self.verbose = verbose
self.importlvl = importlvl
self.lex = lexer.LessLexer()
2012-02-19 20:38:19 +00:00
if not tabfile:
tabfile = 'yacctab'
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
self.ignored = ('css_comment', 'less_comment',
2012-03-23 16:45:28 +00:00
'css_vendor_hack')
2013-07-19 11:21:51 +02:00
self.tokens = [t for t in self.lex.tokens
2012-01-28 14:52:09 +00:00
if t not in self.ignored]
self.parser = ply.yacc.yacc(
2013-07-19 11:21:51 +02:00
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
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
def parse(self, filename='', debuglevel=0):
""" Parse file.
2012-04-06 14:53:38 +00:00
kwargs:
filename (str): File to parse
debuglevel (int): Parser debuglevel
2012-01-28 14:52:09 +00:00
"""
2013-07-19 11:21:51 +02:00
if self.verbose:
print('Compiling target: %s' % filename, file=sys.stderr)
2012-02-12 11:50:57 +00:00
self.scope.push()
2012-01-28 14:52:09 +00:00
self.target = filename
2013-07-19 11:21:51 +02:00
self.result = self.parser.parse(
filename, lexer=self.lex, debug=debuglevel)
2012-04-08 13:17:22 +00:00
self.post_parse()
2013-07-19 11:21:51 +02:00
2012-04-08 13:17:22 +00:00
def post_parse(self):
2012-05-07 13:12:12 +00:00
""" Post parse cycle. nodejs version allows calls to mixins
2013-07-19 11:21:51 +02:00
not yet defined or known to the parser. We defer all calls
2012-05-07 13:12:12 +00:00
to mixins until after first cycle when all names are known.
2012-04-08 13:17:22 +00:00
"""
2012-04-20 14:42:41 +00:00
if self.result:
out = []
for pu in self.result:
try:
out.append(pu.parse(self.scope))
except SyntaxError as e:
self.handle_error(e, 0)
self.result = list(utility.flatten(out))
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
def scopemap(self):
""" Output scopemap.
"""
2012-03-18 10:08:36 +00:00
utility.debug_print(self.result)
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
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]
2013-07-19 11:21:51 +02: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
"""
2013-07-19 11:21:51 +02:00
if isinstance(p[1], list):
2012-03-18 19:05:53 +00:00
if len(p) >= 3:
2013-07-19 11:21:51 +02:00
if isinstance(p[2], list):
2012-03-18 19:05:53 +00:00
p[1].extend(p[2])
else:
p[1].append(p[2])
2012-02-25 17:08:08 +00:00
else:
2013-07-19 11:21:51 +02:00
p[1] = [p[1]]
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2013-07-19 11:21:51 +02:00
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-04-20 14:53:50 +00:00
| import_statement
2012-01-28 14:52:09 +00:00
"""
2012-02-25 17:08:08 +00:00
p[0] = p[1]
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
2012-01-28 14:52:09 +00:00
def p_statement_aux(self, p):
""" statement : css_charset t_ws css_string t_semicolon
| css_namespace t_ws css_string t_semicolon
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)
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
def p_statement_namespace(self, p):
""" statement : css_namespace t_ws word css_string t_semicolon
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)
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
def p_statement_import(self, p):
""" import_statement : css_import t_ws css_string t_semicolon
| css_import t_ws css_string dom t_semicolon
2012-01-28 14:52:09 +00:00
"""
if self.importlvl > 8:
2013-07-19 11:21:51 +02:00
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))
2013-07-19 11:21:51 +02:00
if not fe:
ipath += '.less'
2012-01-28 14:52:09 +00:00
filename = "%s%s%s" % (cpath, os.sep, ipath)
if os.path.exists(filename):
2013-07-19 11:21:51 +02:00
recurse = LessParser(importlvl=self.importlvl + 1,
2012-03-18 19:11:12 +00:00
verbose=self.verbose, scope=self.scope)
2012-01-28 14:52:09 +00:00
recurse.parse(filename=filename, debuglevel=0)
2012-03-23 17:24:47 +00:00
p[0] = recurse.result
2012-01-28 14:52:09 +00:00
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-03-23 17:24:47 +00:00
p[0] = None
2012-01-28 14:52:09 +00:00
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-04-17 12:26:19 +00:00
sys.stdout.flush()
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02: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
"""
2012-04-08 13:17:22 +00:00
p[0] = Block(list(p)[1:-1], p.lineno(3))
2012-02-26 15:50:07 +00:00
self.scope.pop()
2012-04-08 13:17:22 +00:00
self.scope.add_block(p[0])
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
def p_block_replace(self, p):
""" block_decl : identifier t_semicolon
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:
p[0] = block.copy_inner(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-04-08 13:17:22 +00:00
p[0] = Deferred(p[1], None, p.lineno(2))
2013-07-19 11:21:51 +02: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-03-24 17:23:14 +00:00
try:
p[1].parse(self.scope)
except SyntaxError as e:
pass
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]
2013-07-19 11:21:51 +02: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-19 20:38:19 +00:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
2012-04-08 13:17:22 +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-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-04-06 19:23:22 +00:00
""" open_mixin : identifier t_popen mixin_args_list t_pclose brace_open
| identifier t_popen mixin_args_list t_pclose mixin_guard brace_open
2012-01-28 14:52:09 +00:00
"""
2012-03-18 13:21:47 +00:00
p[1].parse(self.scope)
2012-04-09 09:52:46 +00:00
self.scope.current = p[1]
2012-03-18 13:21:47 +00:00
p[0] = [p[1], p[3]]
2012-03-24 18:33:19 +00:00
if len(p) > 6:
p[0].append(p[5])
else:
p[0].append(None)
2013-07-19 11:21:51 +02:00
2012-03-24 17:23:14 +00:00
def p_mixin_guard(self, p):
2012-03-24 18:33:19 +00:00
""" mixin_guard : less_when mixin_guard_cond_list
2012-03-24 17:23:14 +00:00
"""
2012-03-24 18:33:19 +00:00
p[0] = p[2]
2013-07-19 11:21:51 +02:00
2012-03-24 18:33:19 +00:00
def p_mixin_guard_cond_list_aux(self, p):
""" mixin_guard_cond_list : mixin_guard_cond_list t_comma mixin_guard_cond
2012-03-24 18:33:19 +00:00
| mixin_guard_cond_list less_and mixin_guard_cond
"""
p[1].append(p[2])
p[1].append(p[3])
p[0] = p[1]
2013-07-19 11:21:51 +02:00
2012-03-24 18:33:19 +00:00
def p_mixin_guard_cond_list(self, p):
""" mixin_guard_cond_list : mixin_guard_cond
"""
p[0] = [p[1]]
2013-07-19 11:21:51 +02:00
2012-03-25 13:25:05 +00:00
def p_mixin_guard_cond_rev(self, p):
""" mixin_guard_cond : less_not t_popen argument mixin_guard_cmp argument t_pclose
| less_not t_popen argument t_pclose
"""
p[0] = utility.reverse_guard(list(p)[3:-1])
2013-07-19 11:21:51 +02:00
2012-03-24 17:23:14 +00:00
def p_mixin_guard_cond(self, p):
2012-03-24 18:33:19 +00:00
""" mixin_guard_cond : t_popen argument mixin_guard_cmp argument t_pclose
2012-03-24 17:23:14 +00:00
| t_popen argument t_pclose
"""
2012-03-24 18:33:19 +00:00
p[0] = list(p)[2:-1]
2013-07-19 11:21:51 +02:00
2012-03-24 17:23:14 +00:00
def p_mixin_guard_cmp(self, p):
""" mixin_guard_cmp : '>'
| '<'
| '='
| '>' '='
| '=' '<'
2012-03-24 17:23:14 +00:00
"""
2012-03-24 18:33:19 +00:00
p[0] = ''.join(list(p)[1:])
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
def p_call_mixin(self, p):
""" call_mixin : identifier t_popen mixin_args_list t_pclose t_semicolon
2012-01-28 14:52:09 +00:00
"""
2012-04-08 13:17:22 +00:00
p[1].parse(None)
2012-06-04 07:27:53 +00:00
p[0] = Deferred(p[1], p[3], p.lineno(4))
2013-07-19 11:21:51 +02:00
2012-03-13 20:26:35 +00:00
def p_mixin_args_arguments(self, p):
2012-04-06 19:23:22 +00:00
""" mixin_args_list : less_arguments
"""
p[0] = [p[1]]
2013-07-19 11:21:51 +02:00
2012-04-06 19:23:22 +00:00
def p_mixin_args_list_aux(self, p):
""" mixin_args_list : mixin_args_list t_comma mixin_args
| mixin_args_list t_semicolon mixin_args
2012-04-06 19:23:22 +00:00
"""
p[1].extend([p[3]])
p[0] = p[1]
2013-07-19 11:21:51 +02:00
2012-04-06 19:23:22 +00:00
def p_mixin_args_list(self, p):
""" mixin_args_list : mixin_args
2012-03-13 20:26:35 +00:00
"""
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):
2012-04-06 19:23:22 +00:00
""" mixin_args : mixin_args argument
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]]
2013-07-19 11:21:51 +02:00
2012-03-03 15:16:29 +00:00
def p_mixin_args_empty(self, p):
""" mixin_args : empty
"""
p[0] = None
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
def p_mixin_kwarg(self, p):
2013-12-13 17:26:59 +01:00
""" mixin_kwarg : variable t_colon mixin_kwarg_arg_list
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))
2013-07-19 11:21:51 +02:00
2012-04-06 15:13:10 +00:00
def p_margument_list_aux(self, p):
2012-04-06 19:23:22 +00:00
""" mixin_kwarg_arg_list : mixin_kwarg_arg_list argument
2012-04-06 15:13:10 +00:00
"""
p[1].extend(list(p)[2:])
p[0] = p[1]
2013-07-19 11:21:51 +02:00
2012-04-06 15:13:10 +00:00
def p_margument_list(self, p):
2012-04-06 19:23:22 +00:00
""" mixin_kwarg_arg_list : argument
2012-04-06 15:13:10 +00:00
"""
p[0] = [p[1]]
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02: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]
2013-07-19 11:21:51 +02:00
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-04-20 14:53:50 +00:00
| import_statement
2012-01-28 14:52:09 +00:00
"""
2013-07-19 11:21:51 +02:00
p[0] = p[1] if isinstance(p[1], list) else [p[1]]
2012-02-19 20:38:19 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
2012-02-19 20:38:19 +00:00
2012-01-28 14:52:09 +00:00
def p_variable_decl(self, p):
2013-12-13 17:26:59 +01:00
""" variable_decl : variable t_colon style_list t_semicolon
2012-01-28 14:52:09 +00:00
"""
2012-04-08 13:17:22 +00:00
p[0] = Variable(list(p)[1:-1], p.lineno(4))
2012-05-06 09:28:41 +00:00
p[0].parse(self.scope)
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
2012-01-28 14:52:09 +00:00
def p_property_decl(self, p):
""" property_decl : prop_open style_list t_semicolon
| prop_open style_list css_important t_semicolon
| prop_open empty t_semicolon
2012-01-28 14:52:09 +00:00
"""
2012-02-26 15:50:07 +00:00
l = len(p)
2013-07-19 11:21:51 +02:00
p[0] = Property(list(p)[1:-1], p.lineno(l - 1))
2012-03-06 20:23:27 +00:00
def p_property_decl_arguments(self, p):
""" property_decl : prop_open less_arguments t_semicolon
2012-03-06 20:23:27 +00:00
"""
p[0] = Property([p[1], [p[2]]], p.lineno(3))
2013-07-19 11:21:51 +02:00
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])
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
def p_prop_open(self, p):
2013-12-13 17:26:59 +01:00
""" prop_open : property t_colon
| vendor_property t_colon
| word t_colon
2012-01-28 14:52:09 +00:00
"""
2012-02-26 13:20:35 +00:00
p[0] = (p[1][0], '')
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
2012-02-19 20:38:19 +00:00
def p_style_list_aux(self, p):
""" style_list : style_list style
| style_list t_comma 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]
2013-07-19 11:21:51 +02:00
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]]
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
def p_style(self, p):
""" style : expression
| string
2012-02-19 20:38:19 +00:00
| word
| property
| vendor_property
| estring
2012-01-28 14:52:09 +00:00
"""
p[0] = p[1]
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02: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)
2013-07-19 11:21:51 +02:00
2012-03-24 17:23:14 +00:00
def p_identifier_istr(self, p):
""" identifier : t_popen estring t_pclose
2012-03-24 17:23:14 +00:00
"""
p[0] = Identifier(Call([p[2], p[3]]), 0)
2012-02-19 20:38:19 +00:00
def p_identifier_list_aux(self, p):
""" identifier_list : identifier_list t_comma identifier_group
2012-02-19 20:38:19 +00:00
"""
p[1].extend([p[2]])
p[1].extend(p[3])
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2013-07-19 11:21:51 +02:00
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]
2013-07-19 11:21:51 +02:00
2012-03-23 16:45:28 +00:00
def p_identifier_list_keyframe(self, p):
""" identifier_list : css_keyframes t_ws css_ident
| css_keyframes t_ws css_ident t_ws
"""
p[0] = list(p)[1:]
2013-07-19 11:21:51 +02:00
def p_identifier_list_viewport(self, p):
""" identifier_list : css_viewport
| css_viewport t_ws
"""
p[0] = list(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]])
2013-07-19 11:21:51 +02:00
if len(p) > 3:
p[1].extend(p[3])
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2013-07-19 11:21:51 +02:00
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]
2013-07-19 11:21:51 +02: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
"""
2013-07-19 11:21:51 +02:00
if isinstance(p[2], list):
2012-02-19 20:38:19 +00:00
p[1].extend(p[2])
2013-07-19 11:21:51 +02:00
else:
p[1].append(p[2])
2012-01-28 14:52:09 +00:00
p[0] = p[1]
2013-07-19 11:21:51 +02:00
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
"""
2013-07-19 11:21:51 +02:00
if not isinstance(p[1], list):
2012-02-19 20:38:19 +00:00
p[1] = [p[1]]
p[0] = p[1]
2013-07-19 11:21:51 +02:00
2012-02-27 18:48:20 +00:00
def p_ident_media(self, p):
""" ident_parts : css_media t_ws
2013-12-13 17:26:59 +01:00
| css_media t_ws t_popen word t_colon number t_pclose
2012-02-27 18:48:20 +00:00
"""
p[0] = list(p)[1:]
2013-07-19 11:21:51 +02:00
def p_ident_media_var(self, p):
2013-12-13 17:26:59 +01:00
""" ident_parts : css_media t_ws t_popen word t_colon variable t_pclose
"""
p[0] = list(p)[1:]
if utility.is_variable(p[0][5]):
var = self.scope.variables(''.join(p[0][5]))
if var:
p[0][5] = var.value[0]
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]
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
def p_ident_part(self, p):
""" ident_part : iclass
2012-02-19 20:38:19 +00:00
| 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]
2013-07-19 11:21:51 +02:00
def p_ident_part_aux(self, p):
""" ident_part : combinator vendor_property
"""
p[0] = [p[1], p[2]]
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02: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]
2013-07-19 11:21:51 +02:00
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
2013-12-13 17:26:59 +01:00
| t_colon word
| t_colon vendor_property
| t_colon vendor_property t_ws
| t_colon css_property
| t_colon css_property t_ws
| t_colon css_filter
| t_colon t_colon word
| t_colon t_colon vendor_property
2012-02-19 20:38:19 +00:00
"""
p[0] = list(p)[1:]
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
def p_ms_filter(self, p):
""" ms_filter : css_ms_filter
| css_ms_filter t_ws
"""
p[0] = tuple(list(p)[1:])
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
| ms_filter t_popen argument_list t_pclose
2012-01-28 14:52:09 +00:00
"""
2012-02-26 15:50:07 +00:00
p[0] = Call(list(p)[1:], 0)
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
2012-03-15 19:20:04 +00:00
def p_argument_list_empty(self, p):
""" argument_list : empty
"""
p[0] = ''
2013-07-19 11:21:51 +02:00
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 t_comma 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]
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
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]]
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
def p_argument(self, p):
""" argument : expression
| string
| estring
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]
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
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)
2013-07-19 11:21:51 +02:00
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]]
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
def p_expression_p(self, p):
""" expression : t_popen expression t_pclose
"""
p[0] = p[2]
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
def p_expression(self, p):
""" expression : factor
"""
p[0] = p[1]
2013-07-19 11:21:51 +02:00
def p_factor(self, p):
2012-02-19 20:38:19 +00:00
""" factor : color
| number
| variable
| css_dom
| fcall
2012-02-19 20:38:19 +00:00
"""
p[0] = p[1]
2013-07-19 11:21:51 +02:00
2012-02-19 20:38:19 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
2012-02-19 20:38:19 +00:00
def p_escaped_string(self, p):
""" estring : t_eopen style_list t_eclose
| t_eopen identifier_list t_eclose
2012-01-28 14:52:09 +00:00
"""
p[0] = p[2]
2013-07-19 11:21:51 +02:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
def p_string_part(self, p):
""" string_part : variable
| css_string
"""
p[0] = p[1]
def p_string_part_list_aux(self, p):
""" string_part_list : string_part_list string_part
"""
p[1].extend([p[2]])
p[0] = p[1]
def p_string_part_list(self, p):
""" string_part_list : string_part
"""
p[0] = [p[1]]
def p_string_aux(self, p):
""" string : t_isopen string_part_list t_isclose
"""
p[0] = ['"', p[2], '"']
def p_string(self, p):
""" string : css_string
"""
p[0] = p[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
"""
2013-07-19 11:21:51 +02:00
p[0] = ['-', p[2]]
2012-01-28 14:52:09 +00:00
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]
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
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
"""
2012-03-23 17:16:40 +00:00
# p[0] = p[1]
2013-07-19 11:21:51 +02:00
p[0] = tuple(list(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:
2013-07-19 11:21:51 +02:00
p[0] = Color().fmt(p[1])
if len(p) > 2:
p[0] = [p[0], p[2]]
2012-03-13 21:12:09 +00:00
except ValueError:
2013-07-19 11:21:51 +02:00
self.handle_error(
'Illegal color value `%s`' % p[1], p.lineno(1), 'W')
2012-03-13 21:12:09 +00:00
p[0] = p[1]
2013-07-19 11:21:51 +02: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
2013-07-19 11:21:51 +02:00
"""
p[0] = tuple(list(p)[1:])
2012-02-19 20:38:19 +00:00
def p_dom(self, p):
""" dom : css_dom
| css_dom t_ws
"""
2013-07-19 11:21:51 +02:00
p[0] = tuple(list(p)[1:])
2012-02-19 20:38:19 +00:00
def p_word(self, p):
""" word : css_ident
| css_ident t_ws
"""
2013-07-19 11:21:51 +02:00
p[0] = tuple(list(p)[1:])
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
2012-02-19 20:38:19 +00:00
def p_class(self, p):
""" class : css_class
| css_class t_ws
"""
2013-07-19 11:21:51 +02:00
p[0] = tuple(list(p)[1:])
def p_interpolated_class_part(self, p):
""" iclass_part : less_variable
| less_variable t_ws
| class
"""
p[0] = list(p)[1:]
def p_interpolated_class_part_list_aux(self, p):
""" iclass_part_list : iclass_part_list iclass_part
"""
p[1].extend([p[2]])
p[0] = p[1]
def p_interpolated_class_part_list(self, p):
""" iclass_part_list : iclass_part
"""
p[0] = [p[1]]
def p_interpolated_class(self, p):
""" iclass : iclass_part_list
"""
p[0] = p[1]
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
2012-02-19 20:38:19 +00:00
def p_id(self, p):
""" id : css_id
| css_id t_ws
"""
2013-07-19 11:21:51 +02:00
p[0] = tuple(list(p)[1:])
2012-02-19 20:38:19 +00:00
def p_property(self, p):
""" property : css_property
| css_property t_ws
"""
2013-07-19 11:21:51 +02:00
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
"""
2013-07-19 11:21:51 +02:00
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
"""
2013-07-19 11:21:51 +02:00
p[0] = tuple(list(p)[1:])
2012-02-19 20:38:19 +00:00
def p_combinator(self, p):
""" combinator : '&' t_ws
| '&'
"""
2013-07-19 11:21:51 +02:00
p[0] = tuple(list(p)[1:])
2012-02-19 20:38:19 +00:00
def p_child_selector(self, p):
""" child_selector : '>' t_ws
| '>'
"""
2013-07-19 11:21:51 +02:00
p[0] = tuple(list(p)[1:])
2012-02-26 10:59:21 +00:00
def p_general_sibling_selector(self, p):
""" general_sibling_selector : t_tilde t_ws
| t_tilde
2012-02-26 10:59:21 +00:00
"""
2013-07-19 11:21:51 +02:00
p[0] = tuple(list(p)[1:])
2012-01-28 14:52:09 +00:00
def p_scope_open(self, p):
""" brace_open : t_bopen
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]
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
def p_scope_close(self, p):
""" brace_close : t_bclose
2012-01-28 14:52:09 +00:00
"""
p[0] = p[1]
2013-07-19 11:21:51 +02:00
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
2013-07-19 11:21:51 +02:00
2012-01-28 14:52:09 +00:00
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2013-07-19 11:21:51 +02:00
#
2012-01-28 14:52:09 +00:00
def p_error(self, t):
""" Internal error handler
2012-04-06 14:53:38 +00:00
args:
2013-07-19 11:21:51 +02:00
t (Lex token): Error token
2012-01-28 14:52:09 +00:00
"""
2013-07-19 11:21:51 +02:00
if t:
print("\x1b[31mE: %s line: %d, Syntax Error, token: `%s`, `%s`\x1b[0m"
2012-07-07 18:03:53 +00:00
% (self.target, t.lineno, t.type, t.value), file=sys.stderr)
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
2013-07-19 11:21:51 +02:00
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
2012-04-06 14:53:38 +00:00
args:
e (Mixed): Exception or str
line (int): line number
t(str): Error type
2012-01-28 14:52:09 +00:00
"""
2012-03-18 10:08:36 +00:00
# print(e.trace())
2012-07-07 18:03:53 +00:00
color = '\x1b[31m' if t == 'E' else '\x1b[33m'
2013-07-19 11:21:51 +02:00
print("%s%s: line: %d: %s\n" %
(color, t, line, e), end='\x1b[0m', file=sys.stderr)