summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEevee (Alex Munroe) <eevee.git@veekun.com>2013-08-13 11:26:38 -0700
committerEevee (Alex Munroe) <eevee.git@veekun.com>2013-08-13 13:26:11 -0700
commitb7b37db613321444a52f0af3600c136fee144879 (patch)
tree7d7c356e89e208622a8345e85c9e00f7029d73d9
parent6b278fa0870072b8100241ed5b3a5ae36fb7c67f (diff)
downloadpyscss-b7b37db613321444a52f0af3600c136fee144879.tar.gz
Use the parser for parsing @function argspecs.
-rw-r--r--scss/__init__.py28
-rw-r--r--scss/expression.py44
2 files changed, 54 insertions, 18 deletions
diff --git a/scss/__init__.py b/scss/__init__.py
index d8d18af..2100466 100644
--- a/scss/__init__.py
+++ b/scss/__init__.py
@@ -606,20 +606,24 @@ class Scss(object):
if not block.argument:
raise SyntaxError("%s requires a function name (%s)" % (block.directive, rule.file_and_line))
- funct, params, _ = block.argument.partition('(')
- funct = normalize_var(funct.strip())
- params = split_params(depar(params + _))
+ funct, lpar, argstr = block.argument.strip().partition('(')
defaults = {}
new_params = []
- for param in params:
- param, _, default = param.partition(':')
- param = normalize_var(param.strip())
- default = default.strip()
- if param:
- new_params.append(param)
- if default:
- calculator = Calculator(rule.namespace)
- defaults[param] = calculator.parse_expression(default)
+
+ if lpar:
+ # Has arguments; parse them with the argspec rule
+ if not argstr.endswith(')'):
+ raise SyntaxError("Expected ')', found end of line: %r" % (block.argument,))
+ argstr = argstr[:-1]
+
+ calculator = Calculator(rule.namespace)
+ argspec_node = calculator.parse_expression(argstr, target='argspec')
+
+ for var_name, default in argspec_node.iter_def_argspec():
+ new_params.append(var_name)
+ if default is not None:
+ defaults[var_name] = default
+
mixin = [list(new_params), defaults, block.unparsed_contents]
if block.directive == '@function':
def _call(mixin):
diff --git a/scss/expression.py b/scss/expression.py
index 2c5ff73..785ba52 100644
--- a/scss/expression.py
+++ b/scss/expression.py
@@ -148,15 +148,19 @@ class Calculator(object):
# print >>sys.stderr, repr(expr),'==',results,'=='
return results
- def parse_expression(self, expr):
- if expr not in ast_cache:
- parser = SassExpression(SassExpressionScanner())
- parser.reset(expr)
- ast = parser.goal()
+ def parse_expression(self, expr, target='goal'):
+ if expr in ast_cache:
+ return ast_cache[expr]
+ parser = SassExpression(SassExpressionScanner())
+ parser.reset(expr)
+ ast = getattr(parser, target)()
+
+ if target == 'goal':
ast_cache[expr] = ast
- return ast_cache[expr]
+ return ast
+
@@ -334,9 +338,37 @@ class ListLiteral(Expression):
return ListValue(items, separator="," if self.comma else "")
class ArgspecLiteral(Expression):
+ """Contains pairs of argument names and values, as parsed from a function
+ definition or function call.
+
+ Note that the semantics are somewhat ambiguous. Consider parsing:
+
+ $foo, $bar: 3
+
+ If this appeared in a function call, $foo would refer to a value; if it
+ appeared in a function definition, $foo would refer to an existing
+ variable. This it's up to the caller to use the right iteration function.
+ """
def __init__(self, argpairs):
+ # argpairs is a list of 2-tuples, parsed as though this were a function
+ # call, so (variable name as string or None, default value as AST
+ # node).
self.argpairs = argpairs
+ def iter_def_argspec(self):
+ """Interpreting this literal as parsed a function call, yields pairs of
+ (variable name as a string, default value as an AST node or None).
+ """
+ for name, value in self.argpairs:
+ if name is None:
+ # value is actually the name
+ if not isinstance(value, Variable):
+ raise SyntaxError("Function definition argspec contains an expression")
+ name = value.name
+ value = None
+
+ yield name, value
+
def parse_bareword(word):
if word in COLOR_NAMES: