18 m_dry_run(dry_run), m_parser( 0,
ParserMode::
Raw), m_updated(false)
22 m_filename(
std::move(filename)), m_dry_run(dry_run), m_parser( 0,
ParserMode::
Raw), m_updated(false)
73 for (std::size_t i = 1, end = ast.
constList().size(); i < end; ++i)
93 const std::size_t before_count = std::ranges::count(original_code,
'#');
94 const std::size_t after_count = std::ranges::count(
m_output,
'#');
96 if (before_count != after_count)
99 "{}: one or more comments from the original source code seem to have been {} by mistake while formatting {}",
100 fmt::styled(
"Warning", fmt::fg(fmt::color::dark_orange)),
101 before_count > after_count ?
"removed" :
"duplicated",
103 fmt::println(
"Please fill an issue on GitHub: https://github.com/ArkScript-lang/Ark");
141 const std::string formatted =
format(node, 0,
false);
142 const std::size_t max_len =
145 [](
const std::string& lhs,
const std::string& rhs) {
146 return lhs.size() < rhs.size();
149 const std::size_t newlines = std::ranges::count(formatted,
'\n');
173 const auto& child = list[at];
179 if (child.position().start.line - previous_line > 1 && child.comment().empty())
183 if (child.position().start.line - previous_line > 2 && !child.comment().empty())
194 after_newline =
true;
201 case NodeType::Symbol:
204 case NodeType::MutArg:
205 result += fmt::format(
"(mut {})", node.
string());
207 case NodeType::RefArg:
208 result += fmt::format(
"(ref {})", node.
string());
210 case NodeType::Capture:
211 result +=
"&" + node.
string();
213 case NodeType::Keyword:
214 result += std::string(
keywords[
static_cast<std::size_t
>(node.
keyword())]);
216 case NodeType::String:
217 result += fmt::format(
"\"{}\"", node.
string());
219 case NodeType::Number:
220 result += fmt::format(
"{}", node.
number());
223 result +=
formatBlock(node, indent, after_newline);
225 case NodeType::Spread:
226 result += fmt::format(
"...{}", node.
string());
228 case NodeType::Field:
231 for (std::size_t i = 1, end = node.
constList().size(); i < end; ++i)
236 case NodeType::Macro:
240 case NodeType::Namespace:
242 case NodeType::Unused:
254 std::string result =
prefix(indent);
255 for (std::size_t i = 0, end = comment.size(); i < end; ++i)
257 result += comment[i];
258 if (comment[i] ==
'\n' && i != end - 1)
271 if (first.
nodeType() == NodeType::Keyword)
289 case Keyword::Import:
305 std::string formatted_args;
307 if (!args_node.
comment().empty())
309 formatted_args +=
"\n";
311 formatted_args +=
prefix(indent + 1);
314 formatted_args +=
" ";
318 bool comment_in_args =
false;
322 for (std::size_t i = 0, end = args_node.
constList().size(); i < end; ++i)
326 comment_in_args =
true;
328 args +=
format(arg_i, indent + ((comment_in_args || split) ? 1 : 0), i > 0 && (comment_in_args || split));
330 args += (comment_in_args || split) ?
'\n' :
' ';
333 formatted_args += fmt::format(
"({}{})", (comment_in_args ?
"\n" :
""), args);
336 formatted_args +=
format(args_node, indent,
false);
339 return fmt::format(
"(fun{} {})", formatted_args,
format(body_node, indent + 1,
false));
340 return fmt::format(
"(fun{}\n{})", formatted_args,
format(body_node, indent + 1,
true));
345 const auto keyword = std::string(
keywords[
static_cast<std::size_t
>(node.
constList()[0].keyword())]);
348 const std::string formatted_bind =
format(node.
constList()[1], indent,
false);
352 return fmt::format(
"({} {} {})", keyword, formatted_bind,
format(body_node, indent,
false));
353 return fmt::format(
"({} {}\n{})", keyword, formatted_bind,
format(body_node, indent + 1,
true));
361 bool cond_on_newline =
false;
362 std::string formatted_cond =
format(cond_node, indent + 1,
false);
363 if (formatted_cond.find(
'\n') != std::string::npos)
364 cond_on_newline =
true;
366 std::string if_cond_formatted = fmt::format(
369 cond_on_newline ?
"\n" :
" ",
377 if (cond_on_newline || split_then_newline)
378 return fmt::format(
"{}\n{})", if_cond_formatted,
format(then_node, indent + 1,
true));
379 return fmt::format(
"{} {})", if_cond_formatted,
format(then_node, indent + 1,
false));
385 format(then_node, indent + 1,
true),
387 node.
constList()[3].commentAfter().empty() ?
"" : (
"\n" +
prefix(indent)));
395 bool cond_on_newline =
false;
396 std::string formatted_cond =
format(cond_node, indent + 1,
false);
397 if (formatted_cond.find(
'\n') != std::string::npos)
398 cond_on_newline =
true;
403 cond_on_newline ?
"\n" :
" ",
405 format(body_node, indent + 1,
true));
409 format(body_node, indent + 1,
false));
420 const std::size_t inner_indentation = indent + (after_newline ? 1 : 0) + (indent == 0 ? 1 : 0);
422 std::string result =
"{\n";
424 for (std::size_t i = 1, end = node.
constList().size(); i < end; ++i)
432 result +=
format(child, inner_indentation,
true);
439 result +=
"\n" +
prefix(indent) +
"}";
450 if (!package_node.
comment().empty())
451 package += "\n" + formatComment(package_node.comment(), indent + 1) + prefix(indent + 1);
455 for (std::size_t i = 0, end = package_node.
constList().size(); i < end; ++i)
457 package += format(package_node.constList()[i], indent + 1, false);
463 if (symbols.nodeType() == NodeType::Symbol && symbols.string() ==
"*")
467 if (const auto& sym_list = symbols.constList(); !sym_list.empty())
469 const bool comment_after_last = !sym_list.back().commentAfter().empty();
471 for (const auto& sym : sym_list)
473 if (sym.comment().empty())
475 if (comment_after_last)
476 package +=
"\n" + prefix(indent + 1) +
":" + sym.string();
478 package +=
" :" + sym.string();
481 package +=
"\n" + formatComment(sym.comment(), indent + 1) + prefix(indent + 1) +
":" + sym.string();
484 if (comment_after_last)
486 package +=
" " + formatComment(sym_list.back().commentAfter(), 0);
487 package +=
"\n" + prefix(indent + 1);
492 return fmt::format(
"(import{})", package);
497 std::string formatted_sym =
format(node.
constList()[1], indent + 1,
false);
498 if (formatted_sym.find(
'\n') != std::string::npos)
499 return fmt::format(
"(del\n{})", formatted_sym);
500 return fmt::format(
"(del {})", formatted_sym);
505 bool is_list =
false;
506 bool is_dict =
false;
507 bool is_multiline =
false;
509 if (!node.
constList().empty() && node.
constList().front().nodeType() == NodeType::Symbol)
511 if (node.
constList().front().string() ==
"list")
513 else if (node.
constList().front().string() ==
"dict")
517 std::vector<std::string> formatted_args;
518 for (std::size_t i = 1, end = node.
constList().size(); i < end; ++i)
522 if (formatted_args.back().find(
'\n') != std::string::npos || !node.
constList()[i].commentAfter().empty())
526 std::string result = is_list ?
"[" : (
"(" +
format(node.
constList()[0], indent,
false));
530 const std::size_t args_line_length = std::accumulate(
531 formatted_args.begin(),
532 formatted_args.end(),
534 [](
const std::size_t acc,
const std::string& val) {
535 return acc + val.size() + 1_z;
540 for (std::size_t i = 0, end = formatted_args.size(); i < end; ++i)
542 const std::string& formatted_node = formatted_args[i];
545 if (i % 2 == 0 && formatted_args.size() > 2)
548 result +=
" " + formatted_node;
550 else if (is_multiline)
552 else if (is_list && i == 0)
553 result += formatted_node;
555 result +=
" " + formatted_node;
557 if (!node.
constList().back().commentAfter().empty())
558 result +=
"\n" +
prefix(indent);
560 result += is_list ?
"]" :
")";
569 std::string result =
"(macro ";
570 bool after_newline =
false;
572 for (std::size_t i = 0, end = node.
constList().size(); i < end; ++i)
575 after_newline =
false;
577 if (!node.
constList()[i].commentAfter().empty())
580 after_newline =
true;
582 else if (i != end - 1)
Common code for the compiler.
Constants used by ArkScript.
Tools to report code errors nicely to the user.
ArkScript homemade exceptions.
Lots of utilities about the filesystem.
User defined literals for Ark internals.
A node of an Abstract Syntax Tree for ArkScript.
NodeType nodeType() const noexcept
Return the node type.
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.
Keyword keyword() const noexcept
Return the keyword held by the value (if the node type allows it)
const std::string & comment() const noexcept
Return the comment attached to this node, if any.
FileSpan position() const noexcept
Get the span of the node (start and end)
const std::string & commentAfter() const noexcept
Return the comment attached after this node, if any.
double number() const noexcept
Return the number held by the value (if the node type allows it)
void process(const std::string &filename, const std::string &code)
Parse the given code.
const Node & ast() const noexcept
ARK_API void generate(const CodeError &e, std::ostream &os=std::cout, bool colorize=true)
Generate a diagnostic from an error and print it to the standard output.
std::string readFile(const std::string &name)
Helper to read a file.
std::vector< std::string > splitString(const std::string &source, const char sep)
Cut a string into pieces, given a character separator.
@ Raw
Keep all text as is without modifying it (useful for the code formatter)
Keyword
The different keywords available.
constexpr std::array< std::string_view, 9 > keywords
List of available keywords in ArkScript.
CodeError thrown by the compiler (parser, macro processor, optimizer, and compiler itself)
std::size_t line
0-indexed line number