// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:string_scanner/string_scanner.dart';

import 'token.dart';

/// A regular expression matching both whitespace and single-line comments.
///
/// This will only match if consumes at least one character.
final _whitespaceAndSingleLineComments =
    new RegExp(r"([ \t\n]+|//[^\n]*(\n|$))+");

/// A regular expression matching the body of a multi-line comment, after `/*`
/// but before `*/` or a nested `/*`.
///
/// This will only match if it consumes at least one character.
final _multiLineCommentBody = new RegExp(r"([^/*]|/[^*]|\*[^/])+");

/// A regular expression matching a hyphenated identifier.
///
/// This is like a standard Dart identifier, except that it can also contain
/// hyphens.
final _hyphenatedIdentifier = new RegExp(r"[a-zA-Z_-][a-zA-Z0-9_-]*");

/// A scanner that converts a boolean selector string into a stream of tokens.
class Scanner {
  /// The underlying string scanner.
  final SpanScanner _scanner;

  /// The next token to emit.
  Token _next;

  /// Whether the scanner has emitted a [TokenType.endOfFile] token.
  bool _endOfFileEmitted = false;

  Scanner(String selector)
      : _scanner = new SpanScanner(selector);

  /// Returns the next token that will be returned by [next].
  ///
  /// Throws a [StateError] if a [TokenType.endOfFile] token has already been
  /// consumed.
  Token peek() {
    if (_next == null) _next = _getNext();
    return _next;
  }

  /// Consumes and returns the next token in the stream.
  ///
  /// Throws a [StateError] if a [TokenType.endOfFile] token has already been
  /// consumed.
  Token next() {
    var token = _next == null ? _getNext() : _next;
    _endOfFileEmitted = token.type == TokenType.endOfFile;
    _next = null;
    return token;
  }

  /// If the next token matches [type], consumes it and returns `true`;
  /// otherwise, returns `false`.
  ///
  /// Throws a [StateError] if a [TokenType.endOfFile] token has already been
  /// consumed.
  bool scan(TokenType type) {
    if (peek().type != type) return false;
    next();
    return true;
  }

  /// Scan and return the next token in the stream.
  Token _getNext() {
    if (_endOfFileEmitted) throw new StateError("No more tokens.");

    _consumeWhitespace();
    if (_scanner.isDone) {
      return new Token(
          TokenType.endOfFile, _scanner.spanFrom(_scanner.state));
    }

    switch (_scanner.peekChar()) {
      case 0x28 /* ( */: return _scanOperator(TokenType.leftParen);
      case 0x29 /* ) */: return _scanOperator(TokenType.rightParen);
      case 0x3F /* ? */: return _scanOperator(TokenType.questionMark);
      case 0x3A /* : */: return _scanOperator(TokenType.colon);
      case 0x21 /* ! */: return _scanOperator(TokenType.not);
      case 0x7C /* | */: return _scanOr();
      case 0x26 /* & */: return _scanAnd();
      default: return _scanIdentifier();
    }
  }

  /// Scans a single-character operator and returns a token of type [type].
  ///
  /// This assumes that the caller has already verified that the next character
  /// is correct for the given operator.
  Token _scanOperator(TokenType type) {
    var start = _scanner.state;
    _scanner.readChar();
    return new Token(type, _scanner.spanFrom(start));
  }

  /// Scans a `||` operator and returns the appropriate token.
  ///
  /// This validates that the next two characters are `||`.
  Token _scanOr() {
    var start = _scanner.state;
    _scanner.expect("||");
    return new Token(TokenType.or, _scanner.spanFrom(start));
  }

  /// Scans a `&&` operator and returns the appropriate token.
  ///
  /// This validates that the next two characters are `&&`.
  Token _scanAnd() {
    var start = _scanner.state;
    _scanner.expect("&&");
    return new Token(TokenType.and, _scanner.spanFrom(start));
  }

  /// Scans and returns an identifier token.
  Token _scanIdentifier() {
    _scanner.expect(_hyphenatedIdentifier, name: "expression");
    return new IdentifierToken(_scanner.lastMatch[0], _scanner.lastSpan);
  }

  /// Consumes all whitespace and comments immediately following the cursor's
  /// current position.
  void _consumeWhitespace() {
    while (_scanner.scan(_whitespaceAndSingleLineComments) ||
        _multiLineComment()) {
      // Do nothing.
    }
  }

  /// Consumes a single multi-line comment.
  ///
  /// Returns whether or not a comment was consumed.
  bool _multiLineComment() {
    if (!_scanner.scan("/*")) return false;

    while (_scanner.scan(_multiLineCommentBody) || _multiLineComment()) {
      // Do nothing.
    }
    _scanner.expect("*/");

    return true;
  }
}
