content: // Copyright 2016 Google Inc. Use of this source code is governed by an
  // MIT-style license that can be found in the LICENSE file or at
  // https://opensource.org/licenses/MIT.
  
  import 'package:charcode/charcode.dart';
  import 'package:source_span/source_span.dart';
  
  import '../../../visitor/interface/expression.dart';
  import '../expression.dart';
  import 'binary_operation.dart';
  import 'list.dart';
  
  /// A unary operator, as in `+$var` or `not fn()`.
  ///
  /// {@category AST}
  final class UnaryOperationExpression extends Expression {
    /// The operator being invoked.
    final UnaryOperator operator;
  
    /// The operand.
    final Expression operand;
  
    final FileSpan span;
  
    UnaryOperationExpression(this.operator, this.operand, this.span);
  
    T accept<T>(ExpressionVisitor<T> visitor) =>
        visitor.visitUnaryOperationExpression(this);
  
    String toString() {
      var buffer = StringBuffer(operator.operator);
      if (operator == UnaryOperator.not) buffer.writeCharCode($space);
      var operand = this.operand;
      var needsParens = switch (operand) {
        BinaryOperationExpression() ||
        UnaryOperationExpression() ||
        ListExpression(hasBrackets: false, contents: [_, _, ...]) =>
          true,
        _ => false,
      };
      if (needsParens) buffer.write($lparen);
      buffer.write(operand);
      if (needsParens) buffer.write($rparen);
      return buffer.toString();
    }
  }
  
  /// A unary operator constant.
  ///
  /// {@category AST}
  enum UnaryOperator {
    /// The numeric identity operator, `+`.
    plus('plus', '+'),
  
    /// The numeric negation operator, `-`.
    minus('minus', '-'),
  
    /// The leading slash operator, `/`.
    ///
    /// This is a historical artifact.
    divide('divide', '/'),
  
    /// The boolean negation operator, `not`.
    not('not', 'not');
  
    /// The English name of `this`.
    final String name;
  
    /// The Sass syntax for `this`.
    final String operator;
  
    const UnaryOperator(this.name, this.operator);
  
    String toString() => name;
  }
  