diff options
author | Eevee (Alex Munroe) <eevee.git@veekun.com> | 2013-08-13 11:26:38 -0700 |
---|---|---|
committer | Eevee (Alex Munroe) <eevee.git@veekun.com> | 2013-08-13 13:26:11 -0700 |
commit | b7b37db613321444a52f0af3600c136fee144879 (patch) | |
tree | 7d7c356e89e208622a8345e85c9e00f7029d73d9 | |
parent | 6b278fa0870072b8100241ed5b3a5ae36fb7c67f (diff) | |
download | pyscss-b7b37db613321444a52f0af3600c136fee144879.tar.gz |
Use the parser for parsing @function argspecs.
-rw-r--r-- | scss/__init__.py | 28 | ||||
-rw-r--r-- | scss/expression.py | 44 |
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: |