ArkScript
A small, fast, functional and scripting language for video games
Function.cpp
Go to the documentation of this file.
2
3namespace Ark::internal
4{
6 {
7 return node.nodeType() == NodeType::List && node.constList().size() > 0 && node.constList()[0].nodeType() == NodeType::Symbol;
8 }
9
11 {
12 Node& first = node.list()[0];
13 const Node* macro = findNearestMacro(first.string());
14
15 if (macro != nullptr)
16 {
17 if (macro->constList().size() == 2)
18 applyMacroProxy(first);
19 // !{name (args) body}
20 else if (macro->constList().size() == 3)
21 {
22 Node temp_body = macro->constList()[2];
23 Node args = macro->constList()[1];
24 std::size_t args_needed = args.list().size();
25 std::size_t args_given = node.constList().size() - 1; // remove the first (the name of the macro)
26 std::string macro_name = macro->constList()[0].string();
27 bool has_spread = args_needed > 0 && args.list().back().nodeType() == NodeType::Spread;
28
29 // bind node->list() to temp_body using macro->constList()[1]
30 std::unordered_map<std::string, Node> args_applied;
31 std::size_t j = 0;
32 for (std::size_t i = 1, end = node.constList().size(); i < end; ++i)
33 {
34 // by breaking early if we have too many arguments, the args_applied/args_needed check will fail
35 if (j >= args_needed)
36 break;
37
38 const std::string& arg_name = args.list()[j].string();
39 if (args.list()[j].nodeType() == NodeType::Symbol)
40 {
41 args_applied[arg_name] = node.constList()[i];
42 ++j;
43 }
44 else if (args.list()[j].nodeType() == NodeType::Spread)
45 {
46 if (args_applied.find(arg_name) == args_applied.end())
47 {
48 args_applied[arg_name] = Node(NodeType::List);
49 args_applied[arg_name].push_back(Node::getListNode());
50 }
51 // do not move j because we checked before that the spread is always the last one
52 args_applied[arg_name].push_back(node.constList()[i]);
53 }
54 }
55
56 // check argument count
57 if (args_applied.size() + 1 == args_needed && has_spread)
58 {
59 // just a spread we didn't assign
60 args_applied[args.list().back().string()] = Node(NodeType::List);
61 args_applied[args.list().back().string()].push_back(Node::getListNode());
62 }
63
64 if (args_given != args_needed && !has_spread)
65 throwMacroProcessingError("Macro `" + macro_name + "' got " + std::to_string(args_given) + " argument(s) but needed " + std::to_string(args_needed), node);
66 else if (args_applied.size() != args_needed && has_spread)
67 // args_needed - 1 because we do not count the spread as a required argument
68 throwMacroProcessingError("Macro `" + macro_name + "' got " + std::to_string(args_applied.size()) + " argument(s) but needed at least " + std::to_string(args_needed - 1), node);
69
70 if (!args_applied.empty())
71 unify(args_applied, temp_body, nullptr);
72
73 node = evaluate(temp_body, false);
74 applyMacroProxy(node);
75 return true;
76 }
77 }
78 else if (isPredefined(first.string()))
79 {
80 node = evaluate(node, false);
81 return true;
82 }
83
84 return false;
85 }
86}
Executor for List Macros.
bool canHandle(Node &node) override
Checks if the executor can apply a macro on the passed Node.
Definition: Function.cpp:5
bool applyMacro(Node &node) override
Executes macros in the Node if the Executor can handle it.
Definition: Function.cpp:10
Node evaluate(Node &node, bool is_not_body)
Evaluate only the macros.
Definition: Executor.cpp:30
void throwMacroProcessingError(const std::string &message, const Node &node)
Throw a macro processing error.
Definition: Executor.cpp:40
void unify(const std::unordered_map< std::string, Node > &, Node &, Node *)
Applies the spread operator.
Definition: Executor.cpp:35
bool isPredefined(const std::string &symbol)
Check if a given symbol is a predefined macro.
Definition: Executor.cpp:50
const Node * findNearestMacro(const std::string &name) const
Find the nearest macro matching a giving name.
Definition: Executor.cpp:15
bool applyMacroProxy(Node &node)
Execute a node, trying to emplace macros calls.
Definition: Executor.cpp:45
A node of an Abstract Syntax Tree for ArkScript.
Definition: Node.hpp:29
NodeType nodeType() const noexcept
Return the node type.
Definition: Node.cpp:126
static const Node & getListNode()
Provide a statically initialized / correct and guaranteed to be initialized Node representing "Empty ...
Definition: Node.cpp:28
const std::string & string() const noexcept
Return the string held by the value (if the node type allows it)
Definition: Node.cpp:92
const std::vector< Node > & constList() const noexcept
Return the list of sub-nodes held by the node.
Definition: Node.cpp:119
std::vector< Node > & list() noexcept
Return the list of sub-nodes held by the node.
Definition: Node.cpp:114