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');
171 const auto& child = list[at];
177 if (child.position().start.line - previous_line > 1 && child.comment().empty())
181 if (child.position().start.line - previous_line > 2 && !child.comment().empty())
192 after_newline =
true;
199 case NodeType::Symbol:
202 case NodeType::MutArg:
203 result += fmt::format(
"(mut {})", node.
string());
205 case NodeType::RefArg:
206 result += fmt::format(
"(ref {})", node.
string());
208 case NodeType::Capture:
209 result +=
"&" + node.
string();
211 case NodeType::Keyword:
212 result += std::string(
keywords[
static_cast<std::size_t
>(node.
keyword())]);
214 case NodeType::String:
215 result += fmt::format(
"\"{}\"", node.
string());
217 case NodeType::Number:
218 result += fmt::format(
"{}", node.
number());
221 result +=
formatBlock(node, indent, after_newline);
223 case NodeType::Spread:
224 result += fmt::format(
"...{}", node.
string());
226 case NodeType::Field:
229 for (std::size_t i = 1, end = node.
constList().size(); i < end; ++i)
234 case NodeType::Macro:
238 case NodeType::Namespace:
240 case NodeType::Unused:
252 std::string result =
prefix(indent);
253 for (std::size_t i = 0, end = comment.size(); i < end; ++i)
255 result += comment[i];
256 if (comment[i] ==
'\n' && i != end - 1)
269 if (first.
nodeType() == NodeType::Keyword)
287 case Keyword::Import:
303 std::string formatted_args;
305 if (!args_node.
comment().empty())
307 formatted_args +=
"\n";
309 formatted_args +=
prefix(indent + 1);
312 formatted_args +=
" ";
316 bool comment_in_args =
false;
320 for (std::size_t i = 0, end = args_node.
constList().size(); i < end; ++i)
324 comment_in_args =
true;
326 args +=
format(arg_i, indent + ((comment_in_args || split) ? 1 : 0), i > 0 && (comment_in_args || split));
328 args += (comment_in_args || split) ?
'\n' :
' ';
331 formatted_args += fmt::format(
"({}{})", (comment_in_args ?
"\n" :
""), args);
334 formatted_args +=
format(args_node, indent,
false);
337 return fmt::format(
"(fun{} {})", formatted_args,
format(body_node, indent + 1,
false));
338 return fmt::format(
"(fun{}\n{})", formatted_args,
format(body_node, indent + 1,
true));
343 const auto keyword = std::string(
keywords[
static_cast<std::size_t
>(node.
constList()[0].keyword())]);
346 const std::string formatted_bind =
format(node.
constList()[1], indent,
false);
350 return fmt::format(
"({} {} {})", keyword, formatted_bind,
format(body_node, indent,
false));
351 return fmt::format(
"({} {}\n{})", keyword, formatted_bind,
format(body_node, indent + 1,
true));
359 bool cond_on_newline =
false;
360 const std::string formatted_cond =
format(cond_node, indent + 1,
false);
361 if (formatted_cond.find(
'\n') != std::string::npos)
362 cond_on_newline =
true;
364 std::string if_cond_formatted = fmt::format(
367 cond_on_newline ?
"\n" :
" ",
368 cond_on_newline ?
format(cond_node, indent + 1,
true) : formatted_cond);
375 if (cond_on_newline || split_then_newline)
376 return fmt::format(
"{}\n{})", if_cond_formatted,
format(then_node, indent + 1,
true));
377 return fmt::format(
"{} {})", if_cond_formatted,
format(then_node, indent + 1,
false));
383 format(then_node, indent + 1,
true),
385 node.
constList()[3].commentAfter().empty() ?
"" : (
"\n" +
prefix(indent)));
393 bool cond_on_newline =
false;
394 std::string formatted_cond =
format(cond_node, indent + 1,
false);
395 if (formatted_cond.find(
'\n') != std::string::npos)
396 cond_on_newline =
true;
401 cond_on_newline ?
"\n" :
" ",
402 cond_on_newline ?
format(cond_node, indent + 1,
true) : formatted_cond,
403 format(body_node, indent + 1,
true));
407 format(body_node, indent + 1,
false));
418 const std::size_t inner_indentation = indent + (after_newline ? 1 : 0) + (indent == 0 ? 1 : 0);
420 std::string result =
"{\n";
422 for (std::size_t i = 1, end = node.
constList().size(); i < end; ++i)
430 result +=
format(child, inner_indentation,
true);
437 result +=
"\n" +
prefix(indent) +
"}";
448 if (!package_node.
comment().empty())
449 package += "\n" + formatComment(package_node.comment(), indent + 1) + prefix(indent + 1);
453 for (std::size_t i = 0, end = package_node.
constList().size(); i < end; ++i)
455 package += format(package_node.constList()[i], indent + 1, false);
461 if (symbols.nodeType() == NodeType::Symbol && symbols.string() ==
"*")
465 if (const auto& sym_list = symbols.constList(); !sym_list.empty())
467 const bool comment_after_last = !sym_list.back().commentAfter().empty();
469 for (const auto& sym : sym_list)
471 if (sym.comment().empty())
473 if (comment_after_last)
474 package +=
"\n" + prefix(indent + 1) +
":" + sym.string();
476 package +=
" :" + sym.string();
479 package +=
"\n" + formatComment(sym.comment(), indent + 1) + prefix(indent + 1) +
":" + sym.string();
482 if (comment_after_last)
484 package +=
" " + formatComment(sym_list.back().commentAfter(), 0);
485 package +=
"\n" + prefix(indent + 1);
490 return fmt::format(
"(import{})", package);
495 std::string formatted_sym =
format(node.
constList()[1], indent + 1,
false);
496 if (formatted_sym.find(
'\n') != std::string::npos)
497 return fmt::format(
"(del\n{})", formatted_sym);
498 return fmt::format(
"(del {})", formatted_sym);
503 bool is_list =
false;
504 bool is_dict =
false;
505 bool is_multiline =
false;
507 if (!node.
constList().empty() && node.
constList().front().nodeType() == NodeType::Symbol)
509 if (node.
constList().front().string() ==
"list")
511 else if (node.
constList().front().string() ==
"dict")
515 std::vector<std::string> formatted_args;
516 for (std::size_t i = 1, end = node.
constList().size(); i < end; ++i)
520 if (formatted_args.back().find(
'\n') != std::string::npos || !node.
constList()[i].commentAfter().empty())
524 std::string result = is_list ?
"[" : (
"(" +
format(node.
constList()[0], indent,
false));
528 const std::size_t args_line_length = std::accumulate(
529 formatted_args.begin(),
530 formatted_args.end(),
532 [](
const std::size_t acc,
const std::string& val) {
533 return acc + val.size() + 1_z;
538 for (std::size_t i = 0, end = formatted_args.size(); i < end; ++i)
540 const std::string& formatted_node = formatted_args[i];
543 if (i % 2 == 0 && formatted_args.size() > 2)
546 result +=
" " + formatted_node;
548 else if (is_multiline)
550 else if (is_list && i == 0)
551 result += formatted_node;
553 result +=
" " + formatted_node;
555 if (!node.
constList().back().commentAfter().empty())
556 result +=
"\n" +
prefix(indent);
558 result += is_list ?
"]" :
")";
567 std::string result =
"(macro ";
568 bool after_newline =
false;
570 for (std::size_t i = 0, end = node.
constList().size(); i < end; ++i)
573 after_newline =
false;
575 if (!node.
constList()[i].commentAfter().empty())
578 after_newline =
true;
580 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)
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