17 m_dry_run(dry_run), m_parser( 0,
ParserMode::
Raw), m_updated(false), m_logger(
"formatter", 0)
21 m_filename(
std::move(filename)), m_dry_run(dry_run), m_parser( 0,
ParserMode::
Raw), m_updated(false), m_logger(
"formatter", 0)
72 for (std::size_t i = 1, end = ast.
constList().size(); i < end; ++i)
92 const std::size_t before_count = std::ranges::count(original_code,
'#');
93 const std::size_t after_count = std::ranges::count(
m_output,
'#');
95 if (before_count != after_count)
98 "one or more comments from the original source code seem to have been {} by mistake while formatting {}",
99 before_count > after_count ?
"removed" :
"duplicated",
101 m_logger.
warn(
"Please fill an issue on GitHub: https://github.com/ArkScript-lang/Ark");
139 const std::string formatted =
format(node, 0,
false);
140 const std::size_t max_len =
143 [](
const std::string& lhs,
const std::string& rhs) {
144 return lhs.size() < rhs.size();
147 const std::size_t newlines = std::ranges::count(formatted,
'\n');
167 return on_multiple_lines ||
181 const auto& child = list[at];
187 if (child.position().start.line - previous_line > 1 && child.comment().empty())
191 if (child.position().start.line - previous_line > 2 && !child.comment().empty())
198 if (!node.
constList().empty() && node.
constList().front().nodeType() == NodeType::Symbol)
200 const auto& sym = node.
constList().front().string();
218 after_newline =
true;
225 case NodeType::Symbol:
228 case NodeType::MutArg:
229 result += fmt::format(
"(mut {})", node.
string());
231 case NodeType::RefArg:
232 result += fmt::format(
"(ref {})", node.
string());
234 case NodeType::Capture:
235 result +=
"&" + node.
string();
237 case NodeType::Keyword:
238 result += std::string(
keywords[
static_cast<std::size_t
>(node.
keyword())]);
240 case NodeType::String:
243 case NodeType::Number:
244 result += fmt::format(
"{}", node.
number());
247 result +=
formatBlock(node, indent, after_newline);
249 case NodeType::Spread:
250 result += fmt::format(
"...{}", node.
string());
252 case NodeType::Field:
255 for (std::size_t i = 1, end = node.
constList().size(); i < end; ++i)
260 case NodeType::Macro:
264 case NodeType::Namespace:
266 case NodeType::Unused:
278 std::string result =
prefix(indent);
279 for (std::size_t i = 0, end = comment.size(); i < end; ++i)
281 result += comment[i];
282 if (comment[i] ==
'\n' && i != end - 1)
295 if (first.
nodeType() == NodeType::Keyword)
313 case Keyword::Import:
329 std::string formatted_args;
331 if (!args_node.
comment().empty())
333 formatted_args +=
"\n";
335 formatted_args +=
prefix(indent + 1);
338 formatted_args +=
" ";
342 bool comment_in_args =
false;
346 for (std::size_t i = 0, end = args_node.
constList().size(); i < end; ++i)
350 comment_in_args =
true;
352 args +=
format(arg_i, indent + ((comment_in_args || split) ? 1 : 0), i > 0 && (comment_in_args || split));
354 args += (comment_in_args || split) ?
'\n' :
' ';
357 formatted_args += fmt::format(
"({}{})", (comment_in_args ?
"\n" :
""), args);
360 formatted_args +=
format(args_node, indent,
false);
362 const std::string same_line_f =
format(body_node, indent + 1,
false);
364 return fmt::format(
"(fun{} {})", formatted_args, same_line_f);
365 return fmt::format(
"(fun{}\n{})", formatted_args,
format(body_node, indent + 1,
true));
370 const auto keyword = std::string(
keywords[
static_cast<std::size_t
>(node.
constList()[0].keyword())]);
373 const std::string formatted_bind =
format(node.
constList()[1], indent,
false);
376 const std::string same_line_f =
format(body_node, indent,
false);
378 return fmt::format(
"({} {} {})", keyword, formatted_bind, same_line_f);
379 return fmt::format(
"({} {}\n{})", keyword, formatted_bind,
format(body_node, indent + 1,
true));
387 bool cond_on_newline =
false;
388 const std::string formatted_cond =
format(cond_node, indent + 1,
false);
389 if (formatted_cond.find(
'\n') != std::string::npos)
390 cond_on_newline =
true;
392 std::string if_cond_formatted = fmt::format(
395 cond_on_newline ?
"\n" :
" ",
396 cond_on_newline ?
format(cond_node, indent + 1,
true) : formatted_cond);
401 const std::string same_line_f =
format(then_node, indent + 1,
false);
403 if (cond_on_newline || split_then_newline)
404 return fmt::format(
"{}\n{})", if_cond_formatted,
format(then_node, indent + 1,
true));
405 return fmt::format(
"{} {})", if_cond_formatted, same_line_f);
411 format(then_node, indent + 1,
true),
413 node.
constList()[3].commentAfter().empty() ?
"" : (
"\n" +
prefix(indent)));
421 const std::string formatted_cond =
format(cond_node, indent + 1,
false);
427 cond_on_newline ?
"\n" :
" ",
428 cond_on_newline ?
format(cond_node, indent + 1,
true) : formatted_cond,
429 format(body_node, indent + 1,
true));
433 format(body_node, indent + 1,
false));
444 const std::size_t inner_indentation = indent + (after_newline ? 1 : 0) + (indent == 0 ? 1 : 0);
446 std::string result =
"{\n";
448 for (std::size_t i = 1, end = node.
constList().size(); i < end; ++i)
456 result +=
format(child, inner_indentation,
true);
463 result +=
"\n" +
prefix(indent) +
"}";
474 if (!package_node.
comment().empty())
475 package += "\n" + formatComment(package_node.comment(), indent + 1) + prefix(indent + 1);
479 for (std::size_t i = 0, end = package_node.
constList().size(); i < end; ++i)
481 package += format(package_node.constList()[i], indent + 1, false);
487 if (symbols.nodeType() == NodeType::Symbol && symbols.string() ==
"*")
491 if (const auto& sym_list = symbols.constList(); !sym_list.empty())
493 const bool comment_after_last = !sym_list.back().commentAfter().empty();
495 for (const auto& sym : sym_list)
497 if (sym.comment().empty())
499 if (comment_after_last)
500 package +=
"\n" + prefix(indent + 1) +
":" + sym.string();
502 package +=
" :" + sym.string();
505 package +=
"\n" + formatComment(sym.comment(), indent + 1) + prefix(indent + 1) +
":" + sym.string();
508 if (comment_after_last)
510 package +=
" " + formatComment(sym_list.back().commentAfter(), 0);
511 package +=
"\n" + prefix(indent + 1);
516 return fmt::format(
"(import{})", package);
521 std::string formatted_sym =
format(node.
constList()[1], indent + 1,
false);
522 if (formatted_sym.find(
'\n') != std::string::npos)
523 return fmt::format(
"(del\n{})", formatted_sym);
524 return fmt::format(
"(del {})", formatted_sym);
530 bool is_multiline =
false;
532 std::vector<std::string> formatted_args;
533 for (std::size_t i = 1, end = node.
constList().size(); i < end; ++i)
537 if (formatted_args.back().find(
'\n') != std::string::npos || !node.
constList()[i].commentAfter().empty())
545 const std::size_t args_line_length = std::accumulate(
546 formatted_args.begin(),
547 formatted_args.end(),
549 [](
const std::size_t acc,
const std::string& val) {
550 return acc + val.size() + 1_z;
555 for (std::size_t i = 0, end = formatted_args.size(); i < end; ++i)
557 const std::string& formatted_node = formatted_args[i];
560 if (i % 2 == 0 && formatted_args.size() > 2)
563 result +=
" " + formatted_node;
568 if (i % 2 == 1 && formatted_args.size() > 3)
571 result +=
" " + formatted_node;
573 else if (is_multiline)
576 result += formatted_node;
578 result +=
" " + formatted_node;
580 if (!node.
constList().back().commentAfter().empty())
581 result +=
"\n" +
prefix(indent);
592 std::string result =
"(macro ";
593 bool after_newline =
false;
595 for (std::size_t i = 0, end = node.
constList().size(); i < end; ++i)
598 after_newline =
false;
600 if (!node.
constList()[i].commentAfter().empty())
603 after_newline =
true;
605 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.
void warn(const char *fmt, Args &&... args)
Write a warn level log using fmtlib.
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)
bool isRawString() const noexcept
Check if a node is a raw string.
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::cerr, bool colorize=true)
Generate a diagnostic from an error and print it to the standard error 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