ArkScript
A small, fast, functional and scripting language for video games
List.cpp
Go to the documentation of this file.
2 
3 namespace 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  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 
25  // bind node->list() to temp_body using macro->constList()[1]
26  std::unordered_map<std::string, Node> args_applied;
27  std::size_t j = 0;
28  for (std::size_t i = 1, end = node.constList().size(); i < end; ++i)
29  {
30  const std::string& arg_name = args.list()[j].string();
31  if (args.list()[j].nodeType() == NodeType::Symbol)
32  {
33  args_applied[arg_name] = node.constList()[i];
34  ++j;
35  }
36  else if (args.list()[j].nodeType() == NodeType::Spread)
37  {
38  if (args_applied.find(arg_name) == args_applied.end())
39  {
40  args_applied[arg_name] = Node(NodeType::List);
41  args_applied[arg_name].push_back(Node::getListNode());
42  }
43  // do not move j because we checked before that the spread is always the last one
44  args_applied[arg_name].push_back(node.constList()[i]);
45  }
46  }
47 
48  // check argument count
49  if (args_applied.size() + 1 == args.list().size() && args.list().back().nodeType() == NodeType::Spread)
50  {
51  // just a spread we didn't assign
52  args_applied[args.list().back().string()] = Node(NodeType::List);
53  args_applied[args.list().back().string()].push_back(Node::getListNode());
54  }
55  else if (args_applied.size() != args.list().size())
56  {
57  std::size_t args_needed = args.list().size();
58  std::string macro_name = macro->constList()[0].string();
59 
60  if (args.list().back().nodeType() != NodeType::Spread)
61  throwMacroProcessingError("Macro `" + macro_name + "' got " + std::to_string(args_applied.size()) + " argument(s) but needed " + std::to_string(args_needed), *macro);
62  else
63  throwMacroProcessingError("Macro `" + macro_name + "' got " + std::to_string(args_applied.size()) + " argument(s) but needed at least " + std::to_string(args_needed - 1), *macro);
64  }
65 
66  if (!args_applied.empty())
67  unify(args_applied, temp_body, nullptr);
68 
69  node = evaluate(temp_body, false);
70  applyMacroProxy(node);
71  return true;
72  }
73  }
74  else if (isPredefined(first.string()))
75  {
76  node = evaluate(node, false);
77  return true;
78  }
79 
80  return false;
81  }
82 }
Executor for List Macros.
bool applyMacro(Node &node) override
Executes macros in the Node if the Executor can handle it.
Definition: List.cpp:10
bool canHandle(Node &node) override
Checks if the executor can apply a macro on the passed Node.
Definition: List.cpp:5
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
Node * findNearestMacro(const std::string &name)
Find the nearest macro matching a giving name.
Definition: Executor.cpp:15
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
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