#include"command_reg.hpp" #include"ast.hpp" #include<vector> namespace cmd { static void validateArguments(const std::vector<Argument>& args, std::ostream& output) { for (const auto& arg : args) { if (arg.type == ARG_STRING_LITERAL || arg.type == ARG_COMMAND_SUBST) { continue; } if (arg.value.find('(') != std::string::npos || arg.value.find(')') != std::string::npos) { throw std::runtime_error("Invalid syntax: '" + arg.value + "' - parentheses not allowed in arguments. Use quotes for literals or $() for command substitution."); } } } void CommandRegistry::registerCommand(const std::string& name, CommandFunction func) { commands[name] = func; } void CommandRegistry::registerTypedCommand(const std::string& name, TypedCommandFunction func) { typedCommands[name] = func; } void CommandRegistry::registerUserDefinedCommand( const std::string& name, const UserDefinedCommandInfo& info) { userDefinedCommands[name] = info; } bool CommandRegistry::isUserDefinedCommand(const std::string& name) const { return userDefinedCommands.find(name) != userDefinedCommands.end(); } bool CommandRegistry::commandExists(const std::string& name) const { return (commands.find(name) != commands.end()) || (typedCommands.find(name) != typedCommands.end()) || (userDefinedCommands.find(name) != userDefinedCommands.end()) || (externCommands.find(name) != externCommands.end()); } int CommandRegistry::executeCommand(const std::string& name, const std::vector<Argument>& args, std::istream& input, std::ostream& output) { validateArguments(args, output); auto it_typed = typedCommands.find(name); if (it_typed != typedCommands.end()) { return it_typed->second(args, input, output); } auto it_str = commands.find(name); if (it_str != commands.end()) { std::vector<std::string> argValues; argValues.reserve(args.size()); for (auto const & arg : args) { argValues.push_back(arg.value); } return it_str->second(argValues, input, output); } auto it_ud = userDefinedCommands.find(name); if (it_ud != userDefinedCommands.end()) { return executeUserDefinedCommand(name, it_ud->second, args, input, output); } auto it_ext = externCommands.find(name); if (it_ext != externCommands.end()) { return executeExternCommand(name, args, input, output); } throw std::runtime_error("Command not found: " + name); return 1; } void CommandRegistry::registerExternCommand(const std::string& name, const ExternCommandInfo& info) { auto it = commands.find(name); if (it != commands.end()) { throw std::runtime_error("Command " + name + " already registered"); } externCommands[name] = info; } int CommandRegistry::executeExternCommand(const std::string& name, const std::vector<Argument>& args, std::istream& input, std::ostream& output) { auto it = externCommands.find(name); if (it != externCommands.end()) { const auto& info = it->second; if (info.func) { return info.func(args, input, output); } else { output << "Function: " << info.functionName << " not found in library: " << info.libraryPath << "\n"; return 1; } } return 0; } int CommandRegistry::executeUserDefinedCommand( const std::string& name, const UserDefinedCommandInfo& info, const std::vector<Argument>& args, std::istream& input, std::ostream& output) { state::GameState* gameState = state::getGameState(); std::unordered_map<std::string, std::optional<std::string>> origValues; for (size_t i = 0; i < std::min(args.size(), info.parameters.size()); ++i) { const auto& paramName = info.parameters[i]; try { origValues[paramName] = gameState->getVariable(paramName); } catch (const state::StateException&) { origValues[paramName] = std::nullopt; } try { if (args[i].type == ARG_VARIABLE) { std::string val; try { val = gameState->getVariable(args[i].value); } catch (...) { val.clear(); } gameState->setVariable(paramName, val); } else if (args[i].type == ARG_COMMAND_SUBST && args[i].cmdNode) { AstExecutor &executor = AstExecutor::getExecutor(); std::stringstream cmdInput, cmdOutput; executor.executeDirectly(args[i].cmdNode, cmdInput, cmdOutput); std::string result = cmdOutput.str(); while (!result.empty() && (result.back() == '\n' || result.back() == '\r')) { result.pop_back(); } gameState->setVariable(paramName, result); } else { gameState->setVariable(paramName, args[i].value); } } catch (const std::exception& e) { for (auto const & kv : origValues) { if (kv.second.has_value()) gameState->setVariable(kv.first, *kv.second); else gameState->clearVariable(kv.first); } output << name << ": error setting parameter '" << paramName << "': " << e.what() << "\n"; return 1; } } int result = 0; try { AstExecutor &executor = AstExecutor::getExecutor(); for (auto const & kv : userDefinedCommands) { executor.getRegistry() .registerUserDefinedCommand(kv.first, kv.second); } bool previousReturnSignal = executor.getReturnSignal(); executor.setReturnSignal(false); executor.execute(input, output, info.body); result = executor.getLastExitStatus(); executor.setReturnSignal(previousReturnSignal); } catch (const std::exception& e) { output << name << ": execution failed: " << e.what() << "\n"; result = 1; } for (auto const & kv : origValues) { if (kv.second.has_value()) gameState->setVariable(kv.first, *kv.second); else gameState->clearVariable(kv.first); } return result; } std::shared_ptr<Library> &CommandRegistry::getLibrary(const std::string& name){ auto it = libraries.find(name); if (it != libraries.end()) { return it->second; } throw std::runtime_error("Library not found: " + name); } std::shared_ptr<Library> &CommandRegistry::setLibrary(const std::string& name) { auto it = libraries.find(name); if (it != libraries.end()) { return it->second; } libraries[name] = std::make_shared<cmd::Library>(name); return libraries[name]; } void CommandRegistry::printInfo(std::ostream &out) { auto listSorted = [](std::ostream &o, auto &l) -> void { std::vector<std::string> lst; for(auto &f: l) { lst.push_back(f.first); } std::sort(lst.begin(), lst.end()); for(auto &i : lst) { o << "\t" << i << "\n"; } }; out << "Commands {\n"; listSorted(out, this->commands); out << "}\n"; out << "Typed Commands {\n"; listSorted(out, this->typedCommands); out << "}\n"; out << "User Defined Commands {\n"; listSorted(out, this->userDefinedCommands); out << "}\n"; out << "Commands from Libraries {\n"; listSorted(out, this->externCommands); out << "}\n"; } bool CommandRegistry::empty() const { return commands.empty() && typedCommands.empty() && userDefinedCommands.empty(); } }