25 const std::size_t args_needed = args.
list().size();
26 const std::size_t args_given = node.
constList().size() - 1;
27 const std::string macro_name = macro->constList()[0].string();
33 std::unordered_map<std::string, Node> args_applied;
35 for (std::size_t i = 1, end = node.
constList().size(); i < end; ++i)
41 const std::string& arg_name = args.
list()[j].string();
44 args_applied[arg_name] = node.
constList()[i];
49 if (!args_applied.contains(arg_name))
55 args_applied[arg_name].push_back(node.
constList()[i]);
60 if (args_applied.size() + 1 == args_needed && has_spread)
67 if (args_given != args_needed && !has_spread)
68 throwMacroProcessingError(fmt::format(
"Macro `{}' got {} argument(s) but needed {}", macro_name, args_given, args_needed), node);
69 if (args_applied.size() != args_needed && has_spread)
71 throwMacroProcessingError(fmt::format(
"Macro `{}' got {} argument(s) but needed at least {}", macro_name, args_applied.size(), args_needed - 1), node);
73 if (!args_applied.empty())
74 unify(args_applied, temp_body,
nullptr);
90 void FunctionExecutor::unify(
const std::unordered_map<std::string, Node>& map,
Node& target,
Node* parent,
const std::size_t index,
const std::size_t unify_depth)
95 "Max macro unification depth reached ({}). You may have a macro trying to evaluate itself, try splitting your code in multiple nodes.",
101 if (
const auto p = map.find(target.
string()); p != map.end())
106 for (std::size_t i = 0; i < target.
list().size(); ++i)
107 unify(map, target.
list()[i], &target, i, unify_depth + 1);
111 assert(parent !=
nullptr &&
"Parent node should be defined when unifying a spread");
113 Node sub_node = target;
115 unify(map, sub_node, parent, 0, unify_depth + 1);
120 for (std::size_t i = 1, end = sub_node.
list().size(); i < end; ++i)
121 parent->
list().insert(
122 parent->
list().begin() +
static_cast<std::vector<Node>::difference_type
>(index + i),
125 parent->
list().erase(parent->
list().begin() +
static_cast<std::vector<Node>::difference_type
>(index));
Constants used by ArkScript.
Executor for List Macros.
bool canHandle(Node &node) override
bool applyMacro(Node &node, unsigned depth) override
void unify(const std::unordered_map< std::string, Node > &map, Node &target, Node *parent, std::size_t index=0, std::size_t unify_depth=0)
void applyMacroProxy(Node &node, unsigned depth)
Apply a macro on a given node.
static void throwMacroProcessingError(const std::string &message, const Node &node)
Throw a macro processing error.
Node evaluate(Node &node, unsigned depth, bool is_not_body) const
Evaluate only the macros.
const Node * findNearestMacro(const std::string &name) const
Find the nearest macro matching a giving name.
A node of an Abstract Syntax Tree for ArkScript.
NodeType nodeType() const noexcept
Return the node type.
void setNodeType(NodeType type) noexcept
Set the Node Type object.
bool isListLike() const noexcept
Check if the node is a list like node.
const std::string & string() const noexcept
Return the string held by the value (if the node type allows it)
const std::vector< Node > & constList() const noexcept
Return the list of sub-nodes held by the node.
void updateValueAndType(const Node &source) noexcept
Copy a node to the current one, while keeping the filename and position in the file.
std::vector< Node > & list() noexcept
Return the list of sub-nodes held by the node.
constexpr std::array macros
std::string typeToString(const Node &node) noexcept
const Node & getListNode()
constexpr std::size_t MaxMacroUnificationDepth
Controls the number of recursive calls to MacroProcessor::unify.