ArkScript
A small, lisp-inspired, functional scripting language
Node.cpp
Go to the documentation of this file.
3
4#include <Ark/Exceptions.hpp>
5
6#include <cassert>
7#include <fmt/core.h>
8
9namespace Ark::internal
10{
11 Node::Node(const NodeType node_type, const std::string& value) :
12 m_type(node_type), m_value(value)
13 {}
14
15 Node::Node(const NodeType node_type) :
16 m_type(node_type)
17 {
19 m_value = std::vector<Node>();
20 }
21
22 Node::Node(double value) :
23 m_type(NodeType::Number), m_value(value)
24 {}
25
26 Node::Node(const long value) :
27 m_type(NodeType::Number), m_value(static_cast<double>(value))
28 {}
29
31 m_type(NodeType::Keyword), m_value(value)
32 {}
33
34 Node::Node(const Namespace& namespace_) :
35 m_type(NodeType::Namespace), m_value(namespace_)
36 {}
37
38 const std::string& Node::string() const noexcept
39 {
40 return std::get<std::string>(m_value);
41 }
42
43 double Node::number() const noexcept
44 {
45 return std::get<double>(m_value);
46 }
47
48 Keyword Node::keyword() const noexcept
49 {
50 return std::get<Keyword>(m_value);
51 }
52
54 {
55 return std::get<Namespace>(m_value);
56 }
57
58 const Namespace& Node::constArkNamespace() const noexcept
59 {
60 return std::get<Namespace>(m_value);
61 }
62
63 void Node::push_back(const Node& node) noexcept
64 {
65 list().push_back(node);
66 }
67
68 std::vector<Node>& Node::list() noexcept
69 {
70 return std::get<std::vector<Node>>(m_value);
71 }
72
73 const std::vector<Node>& Node::constList() const noexcept
74 {
75 return std::get<std::vector<Node>>(m_value);
76 }
77
78 NodeType Node::nodeType() const noexcept
79 {
80 return m_type;
81 }
82
83 bool Node::isListLike() const noexcept
84 {
86 }
87
88 bool Node::isStringLike() const noexcept
89 {
91 }
92
93 bool Node::isFunction() const noexcept
94 {
95 return m_type == NodeType::List &&
96 !constList().empty() &&
97 constList()[0].nodeType() == NodeType::Keyword &&
98 constList()[0].keyword() == Keyword::Fun;
99 }
100
101 void Node::updateValueAndType(const Node& source) noexcept
102 {
103 m_type = source.m_type;
104 m_value = source.m_value;
105 }
106
107 void Node::setNodeType(const NodeType type) noexcept
108 {
109 m_type = type;
110 }
111
112 void Node::setString(const std::string& value) noexcept
113 {
114 m_value = value;
115 }
116
117 void Node::setPos(const std::size_t line, const std::size_t col) noexcept
118 {
119 m_line = line;
120 m_col = col;
121 }
122
123 void Node::setFilename(const std::string& filename) noexcept
124 {
125 m_filename = filename;
126 }
127
128 Node& Node::attachNearestCommentBefore(const std::string& comment)
129 {
131 return *this;
132 }
133
134 Node& Node::attachCommentAfter(const std::string& comment)
135 {
136 if (!m_after_comment.empty())
137 m_after_comment += "\n";
139 if (!m_after_comment.empty() && m_after_comment.back() == '\n')
140 m_after_comment.pop_back();
141 return *this;
142 }
143
144 void Node::setAltSyntax(const bool toggle)
145 {
146 m_alt_syntax = toggle;
147 }
148
149 void Node::setFunctionKind(bool anonymous)
150 {
151 m_is_anonymous_function = anonymous;
152 }
153
154 bool Node::isAnonymousFunction() const noexcept
155 {
157 }
158
159 bool Node::isAltSyntax() const
160 {
161 return m_alt_syntax;
162 }
163
164 std::size_t Node::line() const noexcept
165 {
166 return m_line;
167 }
168
169 std::size_t Node::col() const noexcept
170 {
171 return m_col;
172 }
173
174 const std::string& Node::filename() const noexcept
175 {
176 return m_filename;
177 }
178
179 const std::string& Node::comment() const noexcept
180 {
181 return m_comment;
182 }
183
184 const std::string& Node::commentAfter() const noexcept
185 {
186 return m_after_comment;
187 }
188
189 std::string Node::repr() const noexcept
190 {
191 std::string data;
192 switch (m_type)
193 {
194 case NodeType::Symbol:
195 data += string();
196 break;
197
199 data += "&" + string();
200 break;
201
203 data += keywords[static_cast<std::size_t>(keyword())];
204 break;
205
206 case NodeType::String:
207 data += "\"" + string() + "\"";
208 break;
209
210 case NodeType::Number:
211 data += fmt::format("{}", number());
212 break;
213
214 case NodeType::List:
215 if (m_alt_syntax)
216 {
217 const auto first = constList().front();
218 char open = 0;
219 if (first.nodeType() == NodeType::Keyword && first.keyword() == Keyword::Begin)
220 open = '{';
221 else if (first.nodeType() == NodeType::Symbol && first.string() == "list")
222 open = '[';
223 else
224 assert(false && "Alt syntax nodes can only be begin or list");
225
226 data += open;
227 for (std::size_t i = 1, end = constList().size(); i < end; ++i)
228 {
229 data += constList()[i].repr();
230 if (i < end - 1)
231 data += " ";
232 }
233
234 if (open == '{')
235 data += "}";
236 else if (open == '[')
237 data += "]";
238 }
239 else
240 {
241 data += "(";
242 for (std::size_t i = 0, end = constList().size(); i < end; ++i)
243 {
244 data += constList()[i].repr();
245 if (i < end - 1)
246 data += " ";
247 }
248 data += ")";
249 }
250 break;
251
252 case NodeType::Field:
253 for (std::size_t i = 0, end = constList().size(); i < end; ++i)
254 {
255 data += constList()[i].repr();
256 if (i < end - 1)
257 data += ".";
258 }
259 break;
260
261 case NodeType::Macro:
262 data += "(macro ";
263 for (std::size_t i = 0, end = constList().size(); i < end; ++i)
264 {
265 data += constList()[i].repr();
266 if (i < end - 1)
267 data += " ";
268 }
269 data += ")";
270 break;
271
272 case NodeType::Spread:
273 data += "..." + string();
274 break;
275
276 // namespace node should not have a representation as it is purely internal,
277 // and it can't be exploited by macros (unless you try passing an import node
278 // to a macro, which should not happen?)
280 data += constArkNamespace().ast->repr();
281 break;
282
283 case NodeType::Unused:
284 break;
285 }
286 return data;
287 }
288
289 std::ostream& Node::debugPrint(std::ostream& os) const noexcept
290 {
291 switch (m_type)
292 {
293 case NodeType::Symbol:
294 os << "Symbol:" << string();
295 break;
296
298 os << "Capture:" << string();
299 break;
300
302 os << "Keyword:";
303 switch (keyword())
304 {
305 case Keyword::Fun: os << "Fun"; break;
306 case Keyword::Let: os << "Let"; break;
307 case Keyword::Mut: os << "Mut"; break;
308 case Keyword::Set: os << "Set"; break;
309 case Keyword::If: os << "If"; break;
310 case Keyword::While: os << "While"; break;
311 case Keyword::Begin: os << "Begin"; break;
312 case Keyword::Import: os << "Import"; break;
313 case Keyword::Del: os << "Del"; break;
314 }
315 break;
316
317 case NodeType::String:
318 os << "String:" << string();
319 break;
320
321 case NodeType::Number:
322 os << "Number:" << number();
323 break;
324
325 case NodeType::List:
326 os << "( ";
327 for (const auto& i : constList())
328 i.debugPrint(os) << " ";
329 os << ")";
330 break;
331
332 case NodeType::Field:
333 os << "( Field ";
334 for (const auto& i : constList())
335 i.debugPrint(os) << " ";
336 os << ")";
337 break;
338
339 case NodeType::Macro:
340 os << "( Macro ";
341 for (const auto& i : constList())
342 i.debugPrint(os) << " ";
343 os << ")";
344 break;
345
346 case NodeType::Spread:
347 os << "Spread:" << string();
348 break;
349
351 {
352 const auto details = constArkNamespace();
353 os << "( Namespace:" << details.name << " ";
354 details.ast->debugPrint(os) << " )";
355 break;
356 }
357
358 case NodeType::Unused:
359 break;
360 }
361 return os;
362 }
363
365 {
366 static const Node TrueNode(NodeType::Symbol, "true");
367 return TrueNode;
368 }
369
371 {
372 static const Node FalseNode(NodeType::Symbol, "false");
373 return FalseNode;
374 }
375
377 {
378 static const Node NilNode(NodeType::Symbol, "nil");
379 return NilNode;
380 }
381
383 {
384 static const Node ListNode(NodeType::Symbol, "list");
385 return ListNode;
386 }
387
388 bool operator==(const Node& A, const Node& B)
389 {
390 if (A.m_type != B.m_type) // should have the same types
391 return false;
392
393 if (A.m_type != NodeType::List)
394 return A.m_value == B.m_value;
395 return false;
396 }
397
398 bool operator<(const Node& A, const Node& B)
399 {
400 if (A.nodeType() != B.nodeType())
401 return (static_cast<int>(A.nodeType()) - static_cast<int>(B.nodeType())) < 0;
402
403 switch (A.nodeType())
404 {
405 case NodeType::Number:
406 [[fallthrough]];
407 case NodeType::Symbol:
408 [[fallthrough]];
409 case NodeType::String:
410 return A.m_value < B.m_value;
411
412 default:
413 return false;
414 }
415 }
416}
Common code for the compiler.
ArkScript homemade exceptions.
AST node used by the parser, optimizer and compiler.
A node of an Abstract Syntax Tree for ArkScript.
Definition Node.hpp:30
NodeType nodeType() const noexcept
Return the node type.
Definition Node.cpp:78
std::string m_after_comment
Comment after node.
Definition Node.hpp:259
bool isAnonymousFunction() const noexcept
Check if a node is an anonymous function.
Definition Node.cpp:154
void setNodeType(NodeType type) noexcept
Set the Node Type object.
Definition Node.cpp:107
bool isListLike() const noexcept
Check if the node is a list like node.
Definition Node.cpp:83
const std::string & filename() const noexcept
Return the filename in which this node was created.
Definition Node.cpp:174
const std::string & string() const noexcept
Return the string held by the value (if the node type allows it)
Definition Node.cpp:38
void setPos(std::size_t line, std::size_t col) noexcept
Set the Position of the node in the text.
Definition Node.cpp:117
const std::vector< Node > & constList() const noexcept
Return the list of sub-nodes held by the node.
Definition Node.cpp:73
void setAltSyntax(bool toggle)
Set the m_alt_syntax flag of the node.
Definition Node.cpp:144
bool m_alt_syntax
Used to tell if a node uses the alternative syntax (if available), eg (begin) / {}...
Definition Node.hpp:260
Keyword keyword() const noexcept
Return the keyword held by the value (if the node type allows it)
Definition Node.cpp:48
void setFunctionKind(bool anonymous)
Set the m_is_anonymous_function flag on the node.
Definition Node.cpp:149
std::string m_comment
Definition Node.hpp:258
NodeType m_type
Definition Node.hpp:253
std::string m_filename
Definition Node.hpp:257
Namespace & arkNamespace() noexcept
Return the namespace held by the value (if the node type allows it)
Definition Node.cpp:53
const std::string & comment() const noexcept
Return the comment attached to this node, if any.
Definition Node.cpp:179
Node & attachNearestCommentBefore(const std::string &comment)
Set the comment field with the nearest comment before this node.
Definition Node.cpp:128
std::string repr() const noexcept
Compute a representation of the node without any comments or additional sugar, colors,...
Definition Node.cpp:189
void setFilename(const std::string &filename) noexcept
Set the original Filename where the node was.
Definition Node.cpp:123
std::size_t m_line
Definition Node.hpp:256
std::ostream & debugPrint(std::ostream &os) const noexcept
Print a node to an output stream with added type annotations.
Definition Node.cpp:289
const Namespace & constArkNamespace() const noexcept
Return the namespace held by the value (if the node type allows it)
Definition Node.cpp:58
bool m_is_anonymous_function
Function nodes are marked as anonymous/non-anonymous by the ASTLowerer, to enable some optimisations.
Definition Node.hpp:261
const std::string & commentAfter() const noexcept
Return the comment attached after this node, if any.
Definition Node.cpp:184
std::size_t col() const noexcept
Get the column at which this node was created.
Definition Node.cpp:169
void push_back(const Node &node) noexcept
Every node has a list as well as a value so we can push_back on all node no matter their type.
Definition Node.cpp:63
bool isStringLike() const noexcept
Check if the node is a string like node.
Definition Node.cpp:88
void setString(const std::string &value) noexcept
Set the String object.
Definition Node.cpp:112
double number() const noexcept
Return the number held by the value (if the node type allows it)
Definition Node.cpp:43
void updateValueAndType(const Node &source) noexcept
Copy a node to the current one, while keeping the filename and position in the file.
Definition Node.cpp:101
bool isFunction() const noexcept
Check if the node is a function.
Definition Node.cpp:93
Node & attachCommentAfter(const std::string &comment)
Set the comment_after field with the nearest comment after this node.
Definition Node.cpp:134
std::size_t line() const noexcept
Get the line at which this node was created.
Definition Node.cpp:164
std::size_t m_col
Definition Node.hpp:256
bool isAltSyntax() const
Check if a node is alt syntax.
Definition Node.cpp:159
std::vector< Node > & list() noexcept
Return the list of sub-nodes held by the node.
Definition Node.cpp:68
bool operator<(const Namespace &, const Namespace &)
Definition Namespace.hpp:27
bool operator==(const Namespace &A, const Namespace &B)
Definition Namespace.hpp:21
NodeType
The different node types available.
Definition Common.hpp:44
const Node & getNilNode()
Definition Node.cpp:376
Keyword
The different keywords available.
Definition Common.hpp:75
const Node & getFalseNode()
Definition Node.cpp:370
const Node & getListNode()
Definition Node.cpp:382
constexpr std::array< std::string_view, 9 > keywords
List of available keywords in ArkScript.
Definition Common.hpp:88
const Node & getTrueNode()
Definition Node.cpp:364
std::shared_ptr< Node > ast
Definition Namespace.hpp:18