Skip to content

Add calc()/min()/max()/clamp()#213

Merged
TylerBrinks merged 1 commit into
TylerBrinks:masterfrom
jhaygood86:feature/calc
Jul 23, 2026
Merged

Add calc()/min()/max()/clamp()#213
TylerBrinks merged 1 commit into
TylerBrinks:masterfrom
jhaygood86:feature/calc

Conversation

@jhaygood86

Copy link
Copy Markdown
Contributor

Feature

calc(), min(), max() and clamp() (CSS Values 4 §10) were rejected everywhere:

width: calc(100% - 20px);
width: clamp(200px, 50%, 500px);
margin-top: calc(10px * 2);
transform: rotate(calc(45deg * 2));

Implementation

  • CalcParser — a recursive-descent parser for the <calc-sum>/<calc-product>/<calc-value> grammar, including nested min/max/clamp and parenthesized groups. Binary +/- require whitespace on both sides; *// don't.
  • CalcTypeChecker — the §10.10 type-checking rules: resolves each expression to a CalcCategory (number/length/percentage/angle/…) or rejects a dimensionally-inconsistent one. It folds pure-number subtrees so a constant divide-by-zero is caught here.
  • CalcValueConverter — accepts a calc expression whose category fits the context, and preserves the authored text. Composed onto the length, line-width, angle, number, length-or-percent, and angle-or-number converters, so support cascades to every property built on them.

Type-checking rejects calc(1px + 1s), calc(10px * 20px), calc(100% / 0), calc(1px +1px) (missing space), calc(5) in a length context, clamp(1px, 2px) (wrong arity), and empty/malformed input.

The evaluation of a calc() against layout context (em/% → pixels) is out of scope for a parser — only parsing, type-checking and serialization are provided.

Dependency

A parenthesized group inside the arguments — calc((100% - 20px) / 3) — needs the nested-parentheses lexer fix ("Fix function tokens terminating at a nested closing parenthesis", #190). This branch includes that one change so it's self-contained; if #190 merges first, it rebases cleanly.

Tests

19 cases in PropertyTests/CalcPropertyTests.cs: calc/min/max/clamp/nesting in a length context, angle-context calc, text preservation, and eight type-check/grammar rejections.

The full suite (1263 existing tests) stays green — wiring calc into the core numeric converters disturbs nothing — and all seven target frameworks build with no new warnings.

calc(), min(), max() and clamp() (CSS Values 4 10) were rejected
everywhere. Add a recursive-descent CalcParser, a CalcTypeChecker
implementing the type-checking rules, and a CalcValueConverter composed
onto the length, line-width, angle, number, length-or-percent and
angle-or-number converters so support cascades to every property built
on them. The authored text is preserved.

Type-checking rejects dimensionally-inconsistent expressions
(calc(1px + 1s), calc(10px * 20px)), division by a constant zero, and
malformed input (missing whitespace around +/-, wrong clamp() arity,
empty). An angle/number expression validates in the corresponding
context.

Includes the nested-parentheses lexer fix (also submitted standalone),
needed so a parenthesized group inside the arguments - calc((100% - 20px)
/ 3) - isn't cut off at the inner ')'. If that merges first, this
rebases cleanly.
@jhaygood86
jhaygood86 marked this pull request as ready for review July 22, 2026 23:24
@TylerBrinks
TylerBrinks merged commit 97aa715 into TylerBrinks:master Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants