💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
4.4 KiB

  1. /*
  2. * Copyright (C) 2017-2019 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper Source Code.
  5. *
  6. * Antkeeper Source Code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper Source Code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef CONSOLE_HPP
  20. #define CONSOLE_HPP
  21. #include <functional>
  22. #include <string>
  23. #include <unordered_map>
  24. #include <utility>
  25. #include <vector>
  26. /**
  27. * Parses an argument string into a typed value.
  28. */
  29. template<class T>
  30. class ArgumentParser
  31. {
  32. public:
  33. static T parse(const std::string& argument);
  34. };
  35. template<>
  36. int ArgumentParser<int>::parse(const std::string& argument);
  37. template<>
  38. unsigned int ArgumentParser<unsigned int>::parse(const std::string& argument);
  39. template<>
  40. long ArgumentParser<long>::parse(const std::string& argument);
  41. template<>
  42. unsigned long ArgumentParser<unsigned long>::parse(const std::string& argument);
  43. template<>
  44. float ArgumentParser<float>::parse(const std::string& argument);
  45. template<>
  46. double ArgumentParser<double>::parse(const std::string& argument);
  47. template<>
  48. std::string ArgumentParser<std::string>::parse(const std::string& argument);
  49. /**
  50. * Parses an argument vector of strings into a tuple of typed values.
  51. */
  52. class ArgumentVectorParser
  53. {
  54. public:
  55. template<class... Args>
  56. static std::tuple<Args...> parse(const std::vector<std::string>& arguments)
  57. {
  58. return parse<Args...>(arguments, std::make_index_sequence<sizeof...(Args)>{});
  59. }
  60. private:
  61. template <class... Args, std::size_t... index>
  62. static std::tuple<Args...> parse(const std::vector<std::string>& arguments, std::index_sequence<index...>)
  63. {
  64. return {ArgumentParser<Args>::parse(arguments[index])...};
  65. }
  66. };
  67. class CommandLinker
  68. {
  69. public:
  70. /**
  71. * Links a function and its arguments together into a single callable object.
  72. */
  73. template<class... Args>
  74. static std::function<void()> link(const std::function<void(Args...)>& function, const std::vector<std::string>& arguments)
  75. {
  76. // Parse argument vectors and store in a tuple
  77. auto parsedArguments = ArgumentVectorParser::parse<Args...>(arguments);
  78. // Return callable object which will invoke the function with the parsed arguments
  79. return std::bind
  80. (
  81. [function, parsedArguments]()
  82. {
  83. std::apply(function, parsedArguments);
  84. }
  85. );
  86. }
  87. };
  88. /**
  89. *
  90. */
  91. class CommandInterpreter
  92. {
  93. public:
  94. /**
  95. * Registers a command.
  96. *
  97. * @param name Name used to invoke the command.
  98. * @param function Function associated with the command.
  99. */
  100. template <class... Args>
  101. void registerCommand(const std::string& name, const std::function<void(Args...)>& function);
  102. template <class... Args>
  103. void registerCommand(const std::string& name, void(*function)(Args...));
  104. /**
  105. * Interprets a line of text as a function call, returning the interpreted command name, argument vector, and callable function object.
  106. *
  107. * @param line Line of text to be interpreted.
  108. */
  109. std::tuple<std::string, std::vector<std::string>, std::function<void()>> interpret(const std::string& line);
  110. private:
  111. template <class Function, class Linker>
  112. void addCommandLinker(const std::string& name, const Function& function, const Linker& linker);
  113. // A command name-keyed map of command linkers
  114. std::unordered_map<std::string, std::function<std::function<void()>(const std::vector<std::string>&)>> linkers;
  115. };
  116. template <class... Args>
  117. void CommandInterpreter::registerCommand(const std::string& name, const std::function<void(Args...)>& function)
  118. {
  119. addCommandLinker(name, function, CommandLinker::link<Args...>);
  120. }
  121. template <class... Args>
  122. void CommandInterpreter::registerCommand(const std::string& name, void(*function)(Args...))
  123. {
  124. addCommandLinker(name, function, CommandLinker::link<Args...>);
  125. }
  126. template <class Function, class Linker>
  127. void CommandInterpreter::addCommandLinker(const std::string& name, const Function& function, const Linker& linker)
  128. {
  129. linkers[name] = std::bind(linker, function, std::placeholders::_1);
  130. }
  131. #endif // CONSOLE_HPP