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)
44 const std::string& arg_name = args.
list()[j].string();
47 args_applied[arg_name] = node.
constList()[i];
52 if (!args_applied.contains(arg_name))
58 args_applied[arg_name].push_back(node.
constList()[i]);
63 if (args_applied.size() + 1 == args_needed && has_spread)
70 if (args_given != args_needed && !has_spread)
71 throwMacroProcessingError(fmt::format(
"Macro `{}' got {} argument(s) but needed {}", macro_name, args_given, args_needed), node);
72 if (args_applied.size() != args_needed && has_spread)
74 throwMacroProcessingError(fmt::format(
"Macro `{}' got {} argument(s) but needed at least {}", macro_name, args_applied.size(), args_needed - 1), node);
76 if (!args_applied.empty())
77 unify(args_applied, temp_body,
nullptr);
106 "Max macro unification depth reached ({}). You may have a macro trying to evaluate itself, try splitting your code in multiple nodes.",
112 if (
const auto p = map.find(target.
string()); p != map.end())
119 if (
const std::string macro_name = target.
list()[0].string(); map.contains(macro_name))
122 "Can not define a macro by reusing the argument name `{}'",
127 unify(map, target.
list().back(), &target, target.
list().size() - 1, unify_depth + 1);
132 for (std::size_t i = 0; i < target.
list().size(); ++i)
133 unify(map, target.
list()[i], &target, i, unify_depth + 1);
138 assert(parent !=
nullptr &&
"Parent node should be defined when unifying a spread");
140 Node sub_node = target;
142 unify(map, sub_node, parent, 0, unify_depth + 1);
145 parent->
list()[index] = sub_node;
150 for (std::size_t i = is_list ? 1 : 0, end = sub_node.
list().size(); i < end; ++i)
151 parent->
list().insert(
152 parent->
list().begin() +
static_cast<std::vector<Node>::difference_type
>(index + i + (is_list ? 0 : 1)),
155 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
Node macroNode(Node &node) override
Returns the macro node that will be expanded.
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.
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
const Node & getListNode()
constexpr std::size_t MaxMacroUnificationDepth
Controls the number of recursive calls to MacroProcessor::unify.