Flush the slash separator proposal to the main spec (#3798)

See #2565
This commit is contained in:
Natalie Weizenbaum 2024-03-07 15:10:59 -08:00
parent bfbb8e91ea
commit bb187794a0
9 changed files with 184 additions and 60 deletions

View File

@ -172,7 +172,7 @@ A number has *known units* unless it has unit `%`.
Replace [the definition of `Potentially Slash-Separated Number`] with the
following:
[the definition of `Potentially Slash-Separated Number`]: ../spec/types/number.md#potentially-slash-separated-number
[the definition of `Potentially Slash-Separated Number`]: slash-separator.md#existing-behavior
A Sass number may be *potentially slash-separated*. If it is, it is associated
with two additional Sass numbers, the *original numerator* and the *original

View File

@ -325,7 +325,7 @@ numbers.
Add `CalcExpression`s, `ClampExpression`s, `CssMinMax`es to the list of operands
of the `/` operator that can create a [potentially slash-separated number].
[potentially slash-separated number]: ../spec/types/number.md#potentially-slash-separated-number
[potentially slash-separated number]: slash-separator.md#existing-behavior
## Syntax

View File

@ -447,24 +447,54 @@ This function is also available as a global function named `hue()`.
hwb($channels)
```
* If `$channels` is not an unbracketed space-separated list, throw an error.
* If `$channels` is an unbracketed slash-separated list:
* If `$channels` does not includes exactly three elements, throw an error.
* If `$channels` doesn't have exactly two elements, throw an error.
Otherwise, let `hwb` be the first element and `alpha` the second element.
* Let `hue` and `whiteness` be the first two elements of `$channels`
* If either `hwb` or `alpha` is a [special variable string], return a plain
CSS function string with the name `"hwb"` and the argument `$channels`.
* If the third element of `$channels` has preserved its status as
two slash-separated numbers:
* If `hwb` is not an unbracketed space-separated list, throw an error.
* Let `blackness` be the number before the slash and `alpha` the number
after the slash.
* If the first element of `hwb` is an unquoted string which is
case-insensitively equal to `from`, return a plain CSS function string
with the name `"hwb"` and the argument `$channels`.
* Otherwise:
* If `hwb` has more than three elements, throw an error.
* Let `blackness` be the third element of `$channels`.
* If `hwb` has fewer than three elements:
* Call `hwb()` with `hue`, `whiteness`, `blackness`, and `alpha` (if it's
defined) as arguments and return the result.
* If any element of `hwb` is a special variable string, return a plain
CSS function string with the name `"hwb"` and the argument `$channels`.
* Otherwise, throw an error.
* Let `hue`, `whiteness`, and `blackness` be the three elements of `hwb`.
* Call `hwb()` with `hue`, `whiteness`, `blackness`, and `alpha` as
arguments and return the result.
* Otherwise, If `$channels` is not an unbracketed space-separated list, throw an error.
* If `$channels` does not includes exactly three elements, throw an error.
* Let `hue` and `whiteness` be the first two elements of `$channels`
* If the third element of `$channels` has preserved its status as
two slash-separated numbers:
* Let `blackness` be the number before the slash and `alpha` the number
after the slash.
* Otherwise:
* Let `blackness` be the third element of `$channels`.
* Call `hwb()` with `hue`, `whiteness`, `blackness`, and `alpha` (if it's
defined) as arguments and return the result.
[special variable string]: ../functions.md#special-variable-string
### `ie-hex-str()`

View File

@ -72,6 +72,7 @@ This function is also available as a global function named `list-separator()`.
slash($elements...)
```
* Emit a deprecation warning.
* If `$elements` contains zero or one values, throw an error.
* Return an unbracketed slash-separated list containing `$elements`.

View File

@ -291,7 +291,8 @@ plain CSS function named `"rgb"` that function is named `"rgba"` instead.
* Call `rgb()` with `red`, `green`, `blue`, and `alpha` as arguments and
return the result.
* If `$channels` is not an unbracketed space-separated list, throw an error.
* Otherwise, if `$channels` is not an unbracketed space-separated list, throw
an error.
* If the first element of `$channels` is an unquoted string which is
case-insensitively equal to `from`, return a plain CSS function string
@ -425,7 +426,8 @@ plain CSS function named `"hsl"` that function is named `"hsla"` instead.
* Call `hsl()` with `hue`, `saturation`, `lightness`, and `alpha` as
arguments and return the result.
* If `$channels` is not an unbracketed space-separated list, throw an error.
* Otherwise, if `$channels` is not an unbracketed space-separated list, throw
an error.
* If the first element of `$channels` is an unquoted string which is
case-insensitively equal to `from`, return a plain CSS function string

View File

@ -5,12 +5,13 @@
* [Definitions](#definitions)
* [Source File](#source-file)
* [Vendor Prefix](#vendor-prefix)
* [Grammar](#grammar)
* [Syntax](#syntax-1)
* [`InterpolatedIdentifier`](#interpolatedidentifier)
* [`InterpolatedUrl`](#interpolatedurl)
* [`Name`](#name)
* [`SpecialFunctionExpression`](#specialfunctionexpression)
* [`PseudoSelector`](#pseudoselector)
* [`ProductExpression`](#productexpression)
* [Procedures](#procedures)
* [Parsing Text](#parsing-text)
* [Parsing Text as CSS](#parsing-text-as-css)
@ -38,7 +39,23 @@ points followed by another U+002D. An identifier only has a vendor prefix if the
final U+002D is followed by additional text. This additional text is referred to
as the *unprefixed identifier*.
## Grammar
## Syntax
Unless otherwise specified, if a grammar production's value is parsed as a
single other named Sass production, then the AST does not contain a
representation of the intermediate production.
> For example, suppose we have the productions:
>
> <x><pre>
> **Foo** ::= Bar '*'?
> **Bar** ::= \<ident-token>
> </pre></x>
>
> Parsing `"ident*"` creates an AST that contains a `Foo` that contains a `Bar`.
> But parsing `"ident"` alone creates an AST that only contains a `Bar`—the
> `Foo` wrapper is removed. (The `Bar` wrapper is *not* removed because
> `<ident-token>` is a CSS production, not a Sass production.)
### `InterpolatedIdentifier`
@ -121,6 +138,12 @@ followed by a parenthesis, it must be parsed as a `SelectorPseudo` or an
No whitespace is allowed anywhere in a `PseudoSelector` except within
parentheses.
### `ProductExpression`
<x><pre>
**ProductExpression** ::= (ProductExpression ('*' | '%'))? UnaryPlusExpression
</pre></x>
## Procedures
### Parsing Text
@ -219,7 +242,6 @@ modifications. The following productions should produce errors:
* All SassScript operations *except for*:
* `/`
* `not`
* `or`
* `and`
@ -249,11 +271,6 @@ SCSS:
* The tokens `not`, `or`, `and`, and `null` should be parsed as unquoted
strings.
> The `/` operation should be parsed as normal. Because variables,
> parentheses, functions that return numbers, and all other arithmetic
> expressions are disallowed, it will always compile to slash-separated values
> rather than performing division.
### Consuming an Identifier
This algorithm consumes input from a stream of [code points][] and returns a

View File

@ -13,12 +13,14 @@
* [`Number`](#number)
* [Procedures](#procedures)
* [Evaluating a `FunctionCall` as a Calculation](#evaluating-a-functioncall-as-a-calculation)
* [Adjusting Slash Precedence](#adjusting-slash-precedence)
* [Evaluating an Expression as a Calculation Value](#evaluating-an-expression-as-a-calculation-value)
* [Simplifying a Calculation](#simplifying-a-calculation)
* [Simplifying a `CalculationValue`](#simplifying-a-calculationvalue)
* [Semantics](#semantics)
* [`FunctionExpression` and `Variable`](#functionexpression-and-variable)
* [`SumExpression` and `ProductExpression`](#sumexpression-and-productexpression)
* [`SlashListExpression`](#slashlistexpression)
* [`SpaceListExpression`](#spacelistexpression)
* [`ParenthesizedExpression`](#parenthesizedexpression)
* [`InterpolatedIdentifier`](#interpolatedidentifier)
@ -32,13 +34,13 @@ An expression is "calculation-safe" if it is one of:
* A [`FunctionExpression`].
* A `ParenthesizedExpression` whose contents is calculation-safe.
* A `SumExpression` whose operands are calculation-safe.
* A `ProductExpression` whose operator is `*` or `/` and whose operands are
* A `ProductExpression` whose operator is `*` and whose operands are
calculation-safe.
* A `Number`.
* A `Variable`.
* An `InterpolatedIdentifier`.
* An unbracketed `SpaceListExpression` with more than one element, whose
elements are all calculation-safe.
* An unbracketed `SpaceListExpression` or `SlashListExpression` with more than
one element, whose elements are all calculation-safe.
[`FunctionExpression`]: ../functions.md#syntax
@ -152,13 +154,71 @@ and returns a number or a calculation.
one or more `RestArgument`s, throw an error.
* Let `calc` be a calculation whose name is the lower-case value of `call`'s
name and whose arguments are the result of evaluating each `Expression` in
`call`'s `ArgumentInvocation` [as a calculation value].
name and whose arguments are the result of "[adjusting slash precedence] in
and then evaluating each `Expression`" in `call`'s `ArgumentInvocation` [as a
calculation value].
[adjusting slash precedence]: #adjusting-slash-precedence
[as a calculation value]: #evaluating-an-expression-as-a-calculation-value
* Return the result of [simplifying](#simplifying-a-calculation) `calc`.
### Adjusting Slash Precedence
This algorithm takes a calculation-safe expression `expression` and returns
another calculation-safe expression with the precedence of
[`SlashListExpression`]s adjusted to match division precedence.
[`SlashListExpression`]: list.md#slashlistexpression
* Return a copy of `expression` except, for each `SlashListExpression`:
* Let `left` be the first element of the list.
* For each remaining element `right`:
* If `left` and `right` are both `SumExpression`s:
* Let `last-left` be the last operand of `left` and `first-right` the
first operand of `right`.
* Set `left` to a `SumExpression` that begins with all operands and
operators of `left` except `last-left`, followed by a
`SlashListExpression` with elements `last-left` and `first-right`,
followed by all operators and operands of `right` except `first-right`.
> For example, `slash-list(1 + 2, 3 + 4)` becomes `1 + (2 / 3) + 4`.
* Otherwise, if `left` is a `SumExpression`:
* Let `last-left` be the last operand of `left`.
* Set `left` to a `SumExpression` that begins with all operands and
operators of `left` except `last-left`, followed by a
`SlashListExpression` with elements `last-left` and `right`.
> For example, `slash-list(1 + 2, 3)` becomes `1 + (2 / 3)`.
* Otherwise, if `right` is a `SumExpression` or a `ProductExpression`:
* Let `first-right` be the first operand of `right`.
* Set `left` to an expression of the same type as `right` that begins a
`SlashListExpression` with elements `left` and `first-right`, followed
by operators and operands of `right` except `first-right`.
> For example, `slash-list(1, 2 * 3)` becomes `(1 / 2) * 3`.
* Otherwise, if `left` is a slash-separated list, add `right` to the end.
* Otherwise, set `left` to a slash-separated list containing `left` and
`right`.
* Replace each element in `left` with the result of adjusting slash precedence
in that element.
* Replace the `SlashListExpression` with `left` in the returned expression.
### Evaluating an Expression as a Calculation Value
This algorithm takes an expression `expression` and returns a
@ -497,6 +557,21 @@ To evaluate a `SumExpresssion` or a `ProductExpression` as a calculation value:
* Return `left`.
### `SlashListExpression`
To evaluate a `SlashListExpression` as a calculation value:
* Let `left` be the result of evaluating the first element of the list as a
calculation value.
* For each remaining element `element`:
* Let `right` be the result of evaluating `element` as a calculation value.
* Set `left` to a `CalcOperation` with operator `"/"`, `left`, and `right`.
* Return `left`.
### `SpaceListExpression`
To evaluate a `SpaceListExpresssion` as a calculation value:

View File

@ -6,6 +6,9 @@
* [List](#list)
* [List Value](#list-value)
* [Index](#index)
* [Syntax](#syntax)
* [Semantics](#semantics)
* [`SlashListExpression`](#slashlistexpression)
## Definitions
@ -44,3 +47,31 @@ absolute value is larger than the length of that list.
> * `"c"`: 3, -1
[integer]: number.md#integer
## Syntax
<x><pre>
**BracketedListExpression** ::= '[' ContainedListExpression ']'
**ContainedListExpression** ::= CommaListExpression ','?
**CommaListExpression** ::= SlashListExpression (',' SlashListExpression)*
**SlashListExpression** ::= SpaceListExpression ('/' SpaceListExpression)*
**SpaceListExpression** ::= SumExpression+
</pre></x>
> Note that `/` may *not* be used in single-element lists the way `,` is. That
> is, `(foo,)` is valid, but `(foo/)` is not.
>
> This defines `/` to bind tighter than `,` but looser than space-separated
> lists. This was chosen because most common uses of `/` in CSS conceptually
> bind looser than space-separated values. The only exception is the [`font`
> shorthand syntax], which is used much more rarely will still work (albeit with
> an unintuitive SassScript representation) with a loose-binding `/`.
>
> [`font` shorthand syntax]: https://developer.mozilla.org/en-US/docs/Web/CSS/font
## Semantics
### `SlashListExpression`
To evaluate a `SlashListExpression`, evaluate each of its `SpaceListExpression`s
and return a slash-separated list that contains each of the results in order.

View File

@ -14,7 +14,6 @@
* [Exact Equality](#exact-equality)
* [Fuzzy Equality](#fuzzy-equality)
* [Integer](#integer)
* [Potentially Slash-Separated Number](#potentially-slash-separated-number)
* [Types](#types)
* [Operations](#operations)
* [Equality](#equality)
@ -210,37 +209,6 @@ If `m` exists, we say that `n`'s *integer value* is the double that represents
> To avoid ambiguity, specification text will generally use the term
> "mathematical integer" when referring to the abstract mathematical objects.
### Potentially Slash-Separated Number
A Sass number may be *potentially slash-separated*. If it is, it is associated
with two additional Sass numbers, the *original numerator* and the *original
denominator*. A number that is not potentially slash-separated is known as
*slash-free*.
A potentially slash-separated number is created when a `ProductExpression` with
a `/` operator is evaluated and each operand is *syntactically* one of the
following:
* a `Number`,
* a [`FunctionCall`], or
* a `ProductExpression` that can itself create potentially slash-separated
numbers.
[`FunctionCall`]: ../functions.md#functioncall
If the result of evaluating the `ProductExpression` is a number, that number is
potentially slash-separated if all of the following are true:
* the results of evaluating both operands were numbers, and
* if either operand was a `FunctionCall`, it was [evaluated as a calculation]
and its name was not `"abs"`, `"max"`, `"min"`, or `"round"`.
[evaluated as a calculation]: calculation.md#evaluating-a-functioncall-as-a-calculation
If both of these are true, the first operand is the original numerator of the
potentially slash-separated number returned by the `/` operator, and the second
is the original denominator.
## Types
The value type known as a *number* has three components: