25 const std::size_t args_needed = args.
constList().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)
43 const std::string& arg_name = args.
constList()[j].string();
44 args_applied[arg_name] = node.
constList()[i];
49 const std::string& arg_name = args.
constList()[j].string();
50 if (!args_applied.contains(arg_name))
56 args_applied[arg_name].push_back(node.
constList()[i]);
61 if (args_applied.size() + 1 == args_needed && has_spread)
68 if (args_given != args_needed && !has_spread)
69 throwMacroProcessingError(fmt::format(
"Macro `{}' got {} argument(s) but needed {}", macro_name, args_given, args_needed), node);
70 if (args_applied.size() != args_needed && has_spread)
72 throwMacroProcessingError(fmt::format(
"Macro `{}' got {} argument(s) but needed at least {}", macro_name, args_applied.size(), args_needed - 1), node);
74 if (!args_applied.empty())
75 unify(args_applied, temp_body,
nullptr);
99 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)
104 "Max macro unification depth reached ({}). You may have a macro trying to evaluate itself, try splitting your code in multiple nodes.",
110 if (
const auto p = map.find(target.
string()); p != map.end())
117 if (
const std::string macro_name = target.
list()[0].string(); map.contains(macro_name))
120 "Can not define a macro by reusing the argument name `{}'",
125 unify(map, target.
list().back(), &target, target.
list().size() - 1, unify_depth + 1);
130 for (std::size_t i = 0; i < target.
list().size(); ++i)
131 unify(map, target.
list()[i], &target, i, unify_depth + 1);
136 assert(parent !=
nullptr &&
"Parent node should be defined when unifying a spread");
138 Node sub_node = target;
140 unify(map, sub_node, parent, 0, unify_depth + 1);
143 parent->
list()[index] = sub_node;
148 for (std::size_t i = is_list ? 1 : 0, end = sub_node.
list().size(); i < end; ++i)
149 parent->
list().insert(
150 parent->
list().begin() +
static_cast<std::vector<Node>::difference_type
>(index + i + (is_list ? 0 : 1)),
153 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.