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);
98 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)
103 "Max macro unification depth reached ({}). You may have a macro trying to evaluate itself, try splitting your code in multiple nodes.",
109 if (
const auto p = map.find(target.
string()); p != map.end())
114 for (std::size_t i = 0; i < target.
list().size(); ++i)
115 unify(map, target.
list()[i], &target, i, unify_depth + 1);
119 assert(parent !=
nullptr &&
"Parent node should be defined when unifying a spread");
121 Node sub_node = target;
123 unify(map, sub_node, parent, 0, unify_depth + 1);
126 parent->
list()[index] = sub_node;
131 for (std::size_t i = is_list ? 1 : 0, end = sub_node.
list().size(); i < end; ++i)
132 parent->
list().insert(
133 parent->
list().begin() +
static_cast<std::vector<Node>::difference_type
>(index + i + (is_list ? 0 : 1)),
136 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.