/*
    This file is part of TON Blockchain Library.
    TON Blockchain Library is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.
    TON Blockchain Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.
    You should have received a copy of the GNU Lesser General Public License
    along with TON Blockchain Library.  If not, see .
    Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "srcread.h"
#include 
#include 
#include 
namespace src {
/*
 *
 *   LEXER
 *
 */
int lexem_is_special(std::string str);  // return 0 if no special lexems are needed
struct Lexem {
  enum { Undefined = -2, Eof = -1, Unknown = 0, Ident = 0, Number = 1, Special = 2, String = 3 };
  int tp;
  int val;
  std::string str;
  SrcLocation loc;
  int classify();
  Lexem(std::string _str = "", const SrcLocation& _loc = {}, int _tp = Unknown, int _val = 0)
      : tp(_tp), val(_val), str(_str), loc(_loc) {
    classify();
  }
  int set(std::string _str = "", const SrcLocation& _loc = {}, int _tp = Unknown, int _val = 0);
  Lexem& clear(const SrcLocation& _loc = {}, int _tp = Unknown, int _val = 0) {
    tp = _tp;
    val = _val;
    loc = _loc;
    str = "";
    return *this;
  }
  bool valid() const {
    return tp != Undefined;
  }
  std::string name_str() const;
  void error(std::string _str) const {
    throw ParseError{loc, _str};
  }
  void error_at(std::string str1, std::string str2) const {
    error(str1 + str + str2);
  }
  static std::string lexem_name_str(int idx);
};
class Lexer {
  SourceReader& src;
  bool eof;
  Lexem lexem, peek_lexem;
  unsigned char char_class[128];
  std::array eol_cmt, cmt_op, cmt_cl;
  std::string multiline_quote;
  enum cc { left_active = 2, right_active = 1, active = 3, allow_repeat = 4, quote_char = 8 };
 public:
  bool eof_found() const {
    return eof;
  }
  Lexer(SourceReader& _src, bool init = false, std::string active_chars = ";,() ~.", std::string eol_cmts = ";;",
        std::string open_cmts = "{-", std::string close_cmts = "-}", std::string quote_chars = "\"",
        std::string multiline_quote = "\"\"\"");
  const Lexem& next();
  const Lexem& cur() const {
    return lexem;
  }
  const Lexem& peek();
  int tp() const {
    return lexem.tp;
  }
  void expect(int exp_tp, const char* msg = 0);
  int classify_char(unsigned c) const {
    return c < 0x80 ? char_class[c] : 0;
  }
  bool is_active(int c) const {
    return (classify_char(c) & cc::active) == cc::active;
  }
  bool is_left_active(int c) const {
    return (classify_char(c) & cc::left_active);
  }
  bool is_right_active(int c) const {
    return (classify_char(c) & cc::right_active);
  }
  bool is_repeatable(int c) const {
    return (classify_char(c) & cc::allow_repeat);
  }
  bool is_quote_char(int c) const {
    return (classify_char(c) & cc::quote_char);
  }
 private:
  void set_spec(std::array& arr, std::string setup);
  bool is_multiline_quote(const char* begin, const char* end);
};
}  // namespace src