ArkScript
A small, lisp-inspired, functional scripting language
Node.cpp
Go to the documentation of this file.
3
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_value(value), m_type(node_type), m_pos()
13 {}
14
15 Node::Node(const NodeType node_type) :
16 m_type(node_type), m_pos()
17 {
19 m_value = std::vector<Node>();
20 }
21
22 Node::Node(double value) :
23 m_value(value), m_type(NodeType::Number), m_pos()
24 {}
25
26 Node::Node(const long value) :
27 m_value(static_cast<double>(value)), m_type(NodeType::Number), m_pos()
28 {}
29
31 m_value(value), m_type(NodeType::Keyword), m_pos()
32 {}
33
34 Node::Node(const Namespace& namespace_) :
35 m_value(namespace_), m_type(NodeType::Namespace), m_pos()
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::isFunction() const noexcept
89 {
90 return m_type == NodeType::List &&
91 !constList().empty() &&
92 constList()[0].nodeType() == NodeType::Keyword &&
93 constList()[0].keyword() == Keyword::Fun;
94 }
95
96 const std::optional<std::string>& Node::getUnqualifiedName() const noexcept
97 {
98 return m_unqualified_name;
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::setUnqualifiedName(const std::string& name) noexcept
113 {
114 m_unqualified_name = name;
115 }
116
117 void Node::setString(const std::string& value) noexcept
118 {
119 m_value = value;
120 }
121
122 void Node::setPositionFrom(const Node& source) noexcept
123 {
124 m_filename = source.m_filename;
125 m_pos = source.m_pos;
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(const bool anonymous)
150 {
151 m_is_anonymous_function = anonymous;
152 }
153
154 bool Node::isAnonymousFunction() const noexcept
155 {
157 }
158
159 void Node::setRawString(const bool is_raw_string)
160 {
161 m_is_raw_string = is_raw_string;
162 }
163
164 bool Node::isRawString() const noexcept
165 {
166 return m_is_raw_string;
167 }
168
169 FileSpan Node::position() const noexcept
170 {
171 return m_pos;
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
198 case NodeType::MutArg:
199 data += "(mut " + string() + ")";
200 break;
201
202 case NodeType::RefArg:
203 data += "(ref " + string() + ")";
204 break;
205
207 data += "&" + string();
208 break;
209
211 data += keywords[static_cast<std::size_t>(keyword())];
212 break;
213
214 case NodeType::String:
215 data += (m_is_raw_string ? "r\"" : "\"") + string() + "\"";
216 break;
217
218 case NodeType::Number:
219 data += fmt::format("{}", number());
220 break;
221
222 case NodeType::List:
223 if (m_alt_syntax)
224 {
225 const auto first = constList().front();
226 char open = 0;
227 if (first.nodeType() == NodeType::Keyword && first.keyword() == Keyword::Begin)
228 open = '{';
229 else if (first.nodeType() == NodeType::Symbol && first.string() == "list")
230 open = '[';
231 else
232 assert(false && "Alt syntax nodes can only be begin or list");
233
234 data += open;
235 for (std::size_t i = 1, end = constList().size(); i < end; ++i)
236 {
237 data += constList()[i].repr();
238 if (i < end - 1)
239 data += " ";
240 }
241
242 if (open == '{')
243 data += "}";
244 else if (open == '[')
245 data += "]";
246 }
247 else
248 {
249 data += "(";
250 for (std::size_t i = 0, end = constList().size(); i < end; ++i)
251 {
252 data += constList()[i].repr();
253 if (i < end - 1)
254 data += " ";
255 }
256 data += ")";
257 }
258 break;
259
260 case NodeType::Field:
261 for (std::size_t i = 0, end = constList().size(); i < end; ++i)
262 {
263 data += constList()[i].repr();
264 if (i < end - 1)
265 data += ".";
266 }
267 break;
268
269 case NodeType::Macro:
270 data += "(macro ";
271 for (std::size_t i = 0, end = constList().size(); i < end; ++i)
272 {
273 data += constList()[i].repr();
274 if (i < end - 1)
275 data += " ";
276 }
277 data += ")";
278 break;
279
280 case NodeType::Spread:
281 data += "..." + string();
282 break;
283
284 // namespace node should not have a representation as it is purely internal,
285 // and it can't be exploited by macros (unless you try passing an import node
286 // to a macro, which should not happen?)
288 data += constArkNamespace().ast->repr();
289 break;
290
291 case NodeType::Unused:
292 break;
293 }
294 return data;
295 }
296
297 std::ostream& Node::debugPrint(std::ostream& os) const noexcept
298 {
299 switch (m_type)
300 {
301 case NodeType::Symbol:
302 os << "Symbol:" << string();
303 break;
304
305 case NodeType::MutArg:
306 os << "MutArg:" << string();
307 break;
308
309 case NodeType::RefArg:
310 os << "RefArg:" << string();
311 break;
312
314 os << "Capture:" << string();
315 break;
316
318 os << "Keyword:";
319 switch (keyword())
320 {
321 case Keyword::Fun: os << "Fun"; break;
322 case Keyword::Let: os << "Let"; break;
323 case Keyword::Mut: os << "Mut"; break;
324 case Keyword::Set: os << "Set"; break;
325 case Keyword::If: os << "If"; break;
326 case Keyword::While: os << "While"; break;
327 case Keyword::Begin: os << "Begin"; break;
328 case Keyword::Import: os << "Import"; break;
329 case Keyword::Del: os << "Del"; break;
330 }
331 break;
332
333 case NodeType::String:
334 if (m_is_raw_string)
335 os << "RawString:" << string();
336 else
337 os << "String:" << string();
338 break;
339
340 case NodeType::Number:
341 os << "Number:" << number();
342 break;
343
344 case NodeType::List:
345 os << "( ";
346 for (const auto& i : constList())
347 i.debugPrint(os) << " ";
348 os << ")";
349 break;
350
351 case NodeType::Field:
352 os << "( Field ";
353 for (const auto& i : constList())
354 i.debugPrint(os) << " ";
355 os << ")";
356 break;
357
358 case NodeType::Macro:
359 os << "( Macro ";
360 for (const auto& i : constList())
361 i.debugPrint(os) << " ";
362 os << ")";
363 break;
364
365 case NodeType::Spread:
366 os << "Spread:" << string();
367 break;
368
370 {
371 const auto details = constArkNamespace();
372 os << "( Namespace:" << details.name << " ";
373 details.ast->debugPrint(os) << " )";
374 break;
375 }
376
377 case NodeType::Unused:
378 break;
379 }
380 return os;
381 }
382
383 bool operator==(const Node& A, const Node& B)
384 {
385 if (A.m_type != B.m_type) // should have the same types
386 return false;
387
388 if (A.m_type != NodeType::List)
389 return A.m_value == B.m_value;
390 return false;
391 }
392
393 bool operator<(const Node& A, const Node& B)
394 {
395 if (A.nodeType() != B.nodeType())
396 return false;
397
398 switch (A.nodeType())
399 {
400 case NodeType::Number:
401 [[fallthrough]];
402 case NodeType::Symbol:
403 [[fallthrough]];
404 case NodeType::String:
405 return A.m_value < B.m_value;
406
407 default:
408 return false;
409 }
410 }
411
413 {
414 static const Node TrueNode(NodeType::Symbol, "true");
415 return TrueNode;
416 }
417
419 {
420 static const Node FalseNode(NodeType::Symbol, "false");
421 return FalseNode;
422 }
423
425 {
426 static const Node NilNode(NodeType::Symbol, "nil");
427 return NilNode;
428 }
429
431 {
432 static const Node ListNode(NodeType::Symbol, "list");
433 return ListNode;
434 }
435}
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:32
NodeType nodeType() const noexcept
Return the node type.
Definition Node.cpp:78
std::string m_after_comment
Comment after node.
Definition Node.hpp:267
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
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:258
Keyword keyword() const noexcept
Return the keyword held by the value (if the node type allows it)
Definition Node.cpp:48
bool isRawString() const noexcept
Check if a node is a raw string.
Definition Node.cpp:164
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:266
NodeType m_type
Definition Node.hpp:257
std::string m_filename
Definition Node.hpp:265
Namespace & arkNamespace() noexcept
Return the namespace held by the value (if the node type allows it)
Definition Node.cpp:53
const std::optional< std::string > & getUnqualifiedName() const noexcept
Get the unqualified name, if it has been set.
Definition Node.cpp:96
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
std::optional< std::string > m_unqualified_name
Used by Capture nodes, to have the FQN in the value, and the captured name here.
Definition Node.hpp:262
void setUnqualifiedName(const std::string &name) noexcept
Set the unqualified name (used by Capture nodes)
Definition Node.cpp:112
void setPositionFrom(const Node &source) noexcept
Position the current node at a given span in a file.
Definition Node.cpp:122
std::ostream & debugPrint(std::ostream &os) const noexcept
Print a node to an output stream with added type annotations.
Definition Node.cpp:297
FileSpan position() const noexcept
Get the span of the node (start and end)
Definition Node.cpp:169
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:259
const std::string & commentAfter() const noexcept
Return the comment attached after this node, if any.
Definition Node.cpp:184
void setRawString(bool is_raw_string)
Set the m_is_raw_string flag on the node.
Definition Node.cpp:159
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
void setString(const std::string &value) noexcept
Set the String object.
Definition Node.cpp:117
double number() const noexcept
Return the number held by the value (if the node type allows it)
Definition Node.cpp:43
bool m_is_raw_string
Strings are by default not raw ; raw strings have all their backslashes escaped.
Definition Node.hpp:260
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:88
Node & attachCommentAfter(const std::string &comment)
Set the comment_after field with the nearest comment after this node.
Definition Node.cpp:134
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:424
Keyword
The different keywords available.
Definition Common.hpp:79
const Node & getFalseNode()
Definition Node.cpp:418
const Node & getListNode()
Definition Node.cpp:430
constexpr std::array< std::string_view, 9 > keywords
List of available keywords in ArkScript.
Definition Common.hpp:92
const Node & getTrueNode()
Definition Node.cpp:412
Describes a span for a node/atom in a file, its start position and end position.
Definition Position.hpp:35
std::shared_ptr< Node > ast
Definition Namespace.hpp:18