#include "macro_engine.h"
#include "parser.h"
#include <sstream>
#include <stdexcept>
#include <iostream>
#include <variant>
namespace macrodown
{
namespace
{
// Helper to split a string by delimiter
std::vector<std::string> split(const std::string& s, char delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(s);
while(std::getline(tokenStream, token, delimiter))
{
// Trim whitespace
size_t first = token.find_first_not_of(" \t");
if(first == std::string::npos) continue;
size_t last = token.find_last_not_of(" \t");
tokens.push_back(token.substr(first, (last - first + 1)));
}
return tokens;
}
// Helper to replace all occurrences of a substring
std::string replace_all(std::string str, const std::string& from, const std::string& to)
{
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos)
{
str.replace(start_pos, from.length(), to);
start_pos += to.length();
}
return str;
}
} // namespace
Evaluator::Evaluator()
{
// Register intrinsic %def macro
defineIntrinsic("def", [this](const std::vector<std::string>& args) -> std::string
{
if(args.size() < 3)
{
return "";
}
std::string name = args[0];
std::string arg_list_str = args[1];
std::string body = args[2];
std::vector<std::string> arg_names = split(arg_list_str, ',');
this->define(name, arg_names, body);
return "";
});
}
void Evaluator::define(const std::string& name, const std::vector<std::string>& args, const std::string& body)
{
macros_[name] = MacroDefinition(name, args, body);
}
void Evaluator::defineIntrinsic(const std::string& name, MacroCallback callback)
{
macros_[name] = MacroDefinition(name, callback);
}
std::string Evaluator::evaluate(const Node& node)
{
return std::visit([this](auto&& arg) -> std::string
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, Text>)
{
return arg.content;
}
else if constexpr (std::is_same_v<T, Macro>)
{
return this->evaluateMacro(arg);
}
else if constexpr (std::is_same_v<T, Group>)
{
std::string result;
for(const auto& child : arg.children)
{
result += this->evaluate(*child);
}
return result;
}
return "";
}, node.data);
}
std::string Evaluator::evaluateMacro(const Macro& macro)
{
auto it = macros_.find(macro.name);
if(it == macros_.end())
{
std::string result = "%" + macro.name;
for(const auto& arg : macro.arguments)
{
result += "{" + evaluate(*arg) + "}";
}
return result;
}
const MacroDefinition& def = it->second;
std::vector<std::string> evaluated_args;
for(const auto& arg : macro.arguments)
{
evaluated_args.push_back(evaluate(*arg));
}
if(def.is_intrinsic)
{
return def.callback(evaluated_args);
}
else
{
std::string body = def.body;
for(size_t i = 0; i < def.arg_names.size(); ++i)
{
std::string placeholder = "%" + def.arg_names[i];
std::string value = (i < evaluated_args.size()) ? evaluated_args[i] : "";
body = replace_all(body, placeholder, value);
}
auto nodes = Parser::parse(body);
std::string result;
for(const auto& n : nodes)
{
result += evaluate(*n);
}
return result;
}
}
} // namespace macrodown