diff --git a/lib/src/callable.dart b/lib/src/callable.dart index 1046e6a4..284209fe 100644 --- a/lib/src/callable.dart +++ b/lib/src/callable.dart @@ -2,13 +2,9 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -import 'ast/sass.dart'; - export 'callable/built_in.dart'; export 'callable/user_defined.dart'; abstract class Callable { String get name; - - ArgumentDeclaration get arguments; } diff --git a/lib/src/callable/built_in.dart b/lib/src/callable/built_in.dart index 8c8cd445..5d5be10e 100644 --- a/lib/src/callable/built_in.dart +++ b/lib/src/callable/built_in.dart @@ -9,12 +9,16 @@ import '../value.dart'; typedef Value _Callback(List arguments); class BuiltInCallable implements Callable { - final _Callback callback; - final String name; - final ArgumentDeclaration arguments; + final List overloads; + final List<_Callback> callbacks; - BuiltInCallable( - this.name, this.arguments, Value callback(List arguments)) - : callback = callback; + BuiltInCallable(String name, ArgumentDeclaration arguments, + Value callback(List arguments)) + : this.overloaded(name, [arguments], [callback]); + + BuiltInCallable.overloaded(this.name, Iterable arguments, + Iterable<_Callback> callbacks) + : overloads = new List.unmodifiable(arguments), + callbacks = new List.unmodifiable(callbacks); } diff --git a/lib/src/functions.dart b/lib/src/functions.dart index 45c2fe64..f01030a7 100644 --- a/lib/src/functions.dart +++ b/lib/src/functions.dart @@ -19,18 +19,48 @@ void defineCoreFunctions(Environment environment) { var blue = arguments[2].assertNumber("blue"); return new SassColor.rgb( - _percentageOrUnitless(red, 255, "red"), - _percentageOrUnitless(green, 255, "green"), - _percentageOrUnitless(blue, 255, "blue")); + _percentageOrUnitless(red, 255, "red").round(), + _percentageOrUnitless(green, 255, "green").round(), + _percentageOrUnitless(blue, 255, "blue").round()); })); + environment.setFunction(new BuiltInCallable.overloaded("rgba", [ + new ArgumentDeclaration([ + new Argument("red"), + new Argument("green"), + new Argument("blue"), + new Argument("alpha") + ]), + new ArgumentDeclaration([new Argument("color"), new Argument("alpha")]), + ], [ + (arguments) { + // TODO: support calc strings + var red = arguments[0].assertNumber("red"); + var green = arguments[1].assertNumber("green"); + var blue = arguments[2].assertNumber("blue"); + var alpha = arguments[3].assertNumber("alpha"); + + return new SassColor.rgb( + _percentageOrUnitless(red, 255, "red").round(), + _percentageOrUnitless(green, 255, "green").round(), + _percentageOrUnitless(blue, 255, "blue").round(), + _percentageOrUnitless(alpha, 1, "alpha")); + }, + (arguments) { + var color = arguments[0].assertColor("color"); + var alpha = arguments[0].assertNumber("alpha"); + + return color.change(alpha: _percentageOrUnitless(alpha, 1, "alpha")); + } + ])); + environment.setFunction(new BuiltInCallable( "inspect", new ArgumentDeclaration([new Argument("value")]), (arguments) => new SassString(arguments.single.toString()))); } -int _percentageOrUnitless(SassNumber number, int max, String name) { +num _percentageOrUnitless(SassNumber number, num max, String name) { num value; if (!number.hasUnits) { value = number.value; @@ -41,5 +71,5 @@ int _percentageOrUnitless(SassNumber number, int max, String name) { '\$$name: Expected $number to have no units or "%".'); } - return value.clamp(0, max).round(); + return value.clamp(0, max); } diff --git a/lib/src/value/color.dart b/lib/src/value/color.dart index a257f164..dcb1f8fe 100644 --- a/lib/src/value/color.dart +++ b/lib/src/value/color.dart @@ -12,13 +12,19 @@ class SassColor extends Value { final int red; final int green; final int blue; + final double alpha; - SassColor.rgb(this.red, this.green, this.blue); + SassColor.rgb(this.red, this.green, this.blue, [double alpha]) + : alpha = alpha ?? 1.0; /*=T*/ accept/**/(ValueVisitor/**/ visitor) => visitor.visitColor(this); SassColor assertColor([String name]) => this; + SassColor change({int red, int green, int blue, double alpha}) => + new SassColor.rgb(red ?? this.red, green ?? this.green, blue ?? this.blue, + alpha ?? this.alpha); + Value plus(Value other) { if (other is! SassNumber && other is! SassColor) return super.plus(other); throw new InternalException('Undefined operation "$this + $other".'); diff --git a/lib/src/visitor/perform.dart b/lib/src/visitor/perform.dart index 3f38fb4b..6f5e01c4 100644 --- a/lib/src/visitor/perform.dart +++ b/lib/src/visitor/perform.dart @@ -766,9 +766,26 @@ class PerformVisitor implements StatementVisitor, ExpressionVisitor { var named = triple.item2; var separator = triple.item3; - _verifyArguments(positional, named, callable.arguments, invocation.span); + int overloadIndex; + for (var i = 0; i < callable.overloads.length - 1; i++) { + try { + _verifyArguments( + positional, named, callable.overloads[i], invocation.span); + overloadIndex = i; + break; + } on SassRuntimeException catch (_) { + continue; + } + } + if (overloadIndex == null) { + _verifyArguments( + positional, named, callable.overloads.last, invocation.span); + overloadIndex = callable.overloads.length - 1; + } - var declaredArguments = callable.arguments.arguments; + var overload = callable.overloads[overloadIndex]; + var callback = callable.callbacks[overloadIndex]; + var declaredArguments = overload.arguments; for (var i = positional.length; i < declaredArguments.length; i++) { var argument = declaredArguments[i]; positional.add( @@ -776,7 +793,7 @@ class PerformVisitor implements StatementVisitor, ExpressionVisitor { } SassArgumentList argumentList; - if (callable.arguments.restArgument != null) { + if (overload.restArgument != null) { var rest = positional.length > declaredArguments.length ? positional.sublist(declaredArguments.length) : const []; @@ -789,8 +806,7 @@ class PerformVisitor implements StatementVisitor, ExpressionVisitor { positional.add(argumentList); } - var result = - _addExceptionSpan(() => callable.callback(positional), invocation.span); + var result = _addExceptionSpan(() => callback(positional), invocation.span); if (argumentList == null) return result; if (named.isEmpty) return result; diff --git a/lib/src/visitor/serialize.dart b/lib/src/visitor/serialize.dart index 43b8d9e2..1ebab4d5 100644 --- a/lib/src/visitor/serialize.dart +++ b/lib/src/visitor/serialize.dart @@ -225,10 +225,17 @@ class _SerializeCssVisitor void visitColor(SassColor value) { // TODO(nweiz): Use color names for named colors. - _buffer.writeCharCode($hash); - _writeHexComponent(value.red); - _writeHexComponent(value.green); - _writeHexComponent(value.blue); + if (value.alpha == 1) { + _buffer.writeCharCode($hash); + _writeHexComponent(value.red); + _writeHexComponent(value.green); + _writeHexComponent(value.blue); + } else { + // TODO: support precision in alpha, make sure we don't write exponential + // notation. + _buffer.write( + "rgb(${value.red}, ${value.green}, ${value.blue}, ${value.alpha})"); + } } void _writeHexComponent(int color) {