text: "use strict";
  
  class Scanner {
    constructor(source) {
      this.source = source;
      this.index = 0;
    }
  
    hasNext() {
      return this.index < this.source.length;
    }
  
    peek() {
      return this.source.charAt(this.index) || "";
    }
  
    next() {
      return this.source.charAt(this.index++) || "";
    }
  
    forward() {
      while (this.hasNext() && this.match(/\s/)) {
        this.index += 1;
      }
    }
  
    match(matcher) {
      if (matcher instanceof RegExp) {
        return matcher.test(this.peek());
      }
      return this.peek() === matcher;
    }
  
    expect(matcher) {
      if (!this.match(matcher)) {
        this.throwUnexpectedToken();
      }
      this.index += 1;
    }
  
    scan(matcher) {
      const target = this.source.substr(this.index);
  
      let result = null;
  
      if (matcher instanceof RegExp) {
        const matched = matcher.exec(target);
  
        if (matched && matched.index === 0) {
          result = matched[0];
        }
      } else if (target.substr(0, matcher.length) === matcher) {
        result = matcher;
      }
  
      if (result) {
        this.index += result.length;
      }
  
      return result;
    }
  
    throwUnexpectedToken() {
      const identifier = this.peek() || "ILLEGAL";
  
      throw new SyntaxError(`Unexpected token: ${identifier}`);
    }
  }
  
  module.exports = Scanner;
  