w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.39k stars 644 forks source link

[css-mixins] `<dashed-function>` syntax seems invalid #10558

Open cdoublev opened 3 weeks ago

cdoublev commented 3 weeks ago

A <dashed-function> is a functional notation whose function name starts with two dashes (U+002D HYPHEN-MINUS). Its syntax is:

--*() = --*( <declaration-value># )

First, I think it should be <dashed-function> = --*( <declaration-value># ).

Second, the CSS Value definition syntax does not allow using * as a wildcard in a function's name.

Solutions I am thinking of:

  1. define the production rule as informative
  2. use syntax similar to functional pseudo selector: <function-name> <declaration-value># ')'

I prefer solution 1 because the syntax of solution 2 represents a list of tokens, whereas productions always represent a list of component values, because all entry points of the CSS parser consume component values from the input list of tokens: you do not match the input against <function-name>, then <declaration-value>#, then <)-token>, but against a function component value. Related: #7016.

cdoublev commented 3 weeks ago

Somewhat related... Sometimes specs:

But it is not explicitly required after using in using ( <dependency-list> ). Obviously there would be a function if the whitespace was omitted, so this may not be worth clarifying. (Please tell me if I should open a separate issue.)

An omitted whitespace between two symbols, eg. <foo><bar>, does not mean that a whitespace in the input is disallowed. My point is that if whitespaces were defined to be disallowed between an expression defining a function's name and (, a syntax like <function-name>(<declaration-value>#) for <dashed-function> would be unambiguous.

Fwiw, I think this would be confusing and error-prone. A simpler solution is to rewrite with using <dependency-block>.

Also note that disallowing a whitespace before a multiplier or '>', or after '<', sets a precedent whereas <foo> +, while a bit confusing, is unambiguous to parse since multipliers are not allowed to appear unquoted in a value definition.

In my humble experience, spec authors often omit whitespace in various cases:

They can all be parsed fine. I expect CSS authors to also omit whitespaces. This may be relaxed later, but perhaps they would appreciate some forgiving syntax. I think functions are the only ambiguous case.

tabatkins commented 3 weeks ago

Re: your whitespace comment, there's a bit more, too. Here's the syntax, currently:

&lt;@function> = @function <<function-name>> [ ( <<parameter-list>> ) ]?
    [ using ( <<dependency-list>> ) ]?
    [ returns <<type>> ]?
{
    <<declaration-rule-list>>
}

In addition to the using detail (using () is allowed, using() is illegal), the main parameters are also separate and optional, so @function --foo () is allowed, but @function --foo() is illegal.

This seems odd; in JS, function foo() {...} is, I think, the most common syntactic form (even tho function foo () {...} is allowed in JS, too). I think we should probably at minimum switch to that; possibly we can allow both forms, if useful. This is a novel syntactic form, so even tho it's kinda unprecedented, that might still be acceptable.

@andruud , did you intend to write both of these locations with that whitespace, or was it unintended?

andruud commented 6 days ago

@cdoublev Thanks for reviewing this spec.

--*() = --*( <declaration-value># )

Yeah, I had no idea how to express the thing that needed expressing here. This was inspired by --* from css-variables-1. <dashed-function> = --*( <declaration-value># ) looks better.

What does it mean to mark it informative, and how do I do that?

@andruud , did you intend to write both of these locations with that whitespace, or was it unintended?

Not exactly intentional. I based this on Miriam's explainer, and then forgot to think about whitespace while copying that grammar.

I agree that @function --foo() should work. And probably it should be the only valid form?

Not sure if that means we should require using( as well. Although really I'm hoping we can find an alternatively way to represent the dependencies which avoids the issue.

cdoublev commented 6 days ago

Tab already marked it as non-normative with the informative class. Now w3c/reffy no longer extracts it from the spec.

If I am not mistaken, <dashed-function> will never be included in other value definitions, like other substitution functions. So this issue may therefore be considered fixed.

But since it must be syntactically validated, it would be nice to define its syntax using a normative value definition.

Fwiw, I like Tab's idea. This requires disallowing function names like not, and, or, right? This would fix #7016 by replacing <function-token> <any-value> <)-token> with <ident> (<any-value>).