diff --git a/lib/src/ast/sass/expression/calculation.dart b/lib/src/ast/sass/expression/calculation.dart index ac17dc0aa..55c5b969a 100644 --- a/lib/src/ast/sass/expression/calculation.dart +++ b/lib/src/ast/sass/expression/calculation.dart @@ -50,6 +50,10 @@ class CalculationExpression implements Expression { } } + /// Returns a `sqrt()` calculation expression. + CalculationExpression.sqrt(Expression argument, FileSpan span) + : this("sqrt", [argument], span); + /// Returns a `clamp()` calculation expression. CalculationExpression.clamp( Expression min, Expression value, Expression max, FileSpan span) diff --git a/lib/src/functions/math.dart b/lib/src/functions/math.dart index 5b7fa15f5..fd4bdf40f 100644 --- a/lib/src/functions/math.dart +++ b/lib/src/functions/math.dart @@ -12,6 +12,7 @@ import '../deprecation.dart'; import '../evaluation_context.dart'; import '../exception.dart'; import '../module/built_in.dart'; +import '../util/number.dart'; import '../value.dart'; /// The global definitions of Sass math functions. @@ -144,11 +145,7 @@ final _pow = _function("pow", r"$base, $exponent", (arguments) { final _sqrt = _function("sqrt", r"$number", (arguments) { var number = arguments[0].assertNumber("number"); - if (number.hasUnits) { - throw SassScriptException("\$number: Expected $number to have no units."); - } else { - return SassNumber(math.sqrt(number.value)); - } + return sqrt(number); }); /// diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index 0a4286687..04edf310e 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -2894,6 +2894,7 @@ abstract class StylesheetParser extends Parser { assert(scanner.peekChar() == $lparen); switch (name) { case "calc": + case "sqrt": var arguments = _calculationArguments(1); return CalculationExpression(name, arguments, scanner.spanFrom(start)); diff --git a/lib/src/util/number.dart b/lib/src/util/number.dart index 80fd3aaa2..448ce7a53 100644 --- a/lib/src/util/number.dart +++ b/lib/src/util/number.dart @@ -118,3 +118,9 @@ double moduloLikeSass(double num1, double num2) { var result = num1 % num2; return result == 0 ? 0 : result + num2; } + +/// Return square root of [number] +SassNumber sqrt(SassNumber number) { + number.assertNoUnits(); + return SassNumber(math.sqrt(number.value)); +} diff --git a/lib/src/value/calculation.dart b/lib/src/value/calculation.dart index 74375b280..ca6a51667 100644 --- a/lib/src/value/calculation.dart +++ b/lib/src/value/calculation.dart @@ -6,7 +6,7 @@ import 'package:meta/meta.dart'; import '../exception.dart'; import '../util/nullable.dart'; -import '../util/number.dart'; +import '../util/number.dart' as number; import '../utils.dart'; import '../value.dart'; import '../visitor/interface/value.dart'; @@ -120,6 +120,23 @@ class SassCalculation extends Value { return SassCalculation._("max", args); } + /// Creates a `sqrt()` calculation with the given [argument]. + /// + /// Each argument must be either a [SassNumber], a [SassCalculation], an + /// unquoted [SassString], a [CalculationOperation], or a + /// [CalculationInterpolation]. It must be passed at least one argument. + /// + /// This automatically simplifies the calculation, so it may return a + /// [SassNumber] rather than a [SassCalculation]. It throws an exception if it + /// can determine that the calculation will definitely produce invalid CSS. + static Value sqrt(Object argument) { + argument = _simplify(argument); + if (argument is! SassNumber) { + return SassCalculation._("sqrt", [argument]); + } + return number.sqrt(argument); + } + /// Creates a `clamp()` calculation with the given [min], [value], and [max]. /// /// Each argument must be either a [SassNumber], a [SassCalculation], an @@ -202,7 +219,7 @@ class SassCalculation extends Value { _verifyCompatibleNumbers([left, right]); - if (right is SassNumber && fuzzyLessThan(right.value, 0)) { + if (right is SassNumber && number.fuzzyLessThan(right.value, 0)) { right = right.times(SassNumber(-1)); operator = operator == CalculationOperator.plus ? CalculationOperator.minus diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index e16be1342..3069ac0f4 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -2303,6 +2303,9 @@ class _EvaluateVisitor case "calc": assert(arguments.length == 1); return SassCalculation.calc(arguments[0]); + case "sqrt": + assert(arguments.length == 1); + return SassCalculation.sqrt(arguments[0]); case "min": return SassCalculation.min(arguments); case "max": diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index 0b4e78125..c503d9505 100644 --- a/lib/src/visitor/evaluate.dart +++ b/lib/src/visitor/evaluate.dart @@ -2292,6 +2292,9 @@ class _EvaluateVisitor case "calc": assert(arguments.length == 1); return SassCalculation.calc(arguments[0]); + case "sqrt": + assert(arguments.length == 1); + return SassCalculation.sqrt(arguments[0]); case "min": return SassCalculation.min(arguments); case "max":