// Entry point for prettification. static wcstring prettify(const wcstring &src, bool do_indent) { parse_node_tree_t parse_tree; int parse_flags = (parse_flag_continue_after_error | parse_flag_include_comments | parse_flag_leave_unterminated | parse_flag_show_blank_lines); if (!parse_tree_from_string(src, parse_flags, &parse_tree, NULL)) { return src; // we return the original string on failure } if (dump_parse_tree) { const wcstring dump = parse_dump_tree(parse_tree, src); fwprintf(stderr, L"%ls\n", dump.c_str()); } // We may have a forest of disconnected trees on a parse failure. We have to handle all nodes // that have no parent, and all parse errors. bool has_new_line = true; wcstring result; for (node_offset_t i = 0; i < parse_tree.size(); i++) { const parse_node_t &node = parse_tree.at(i); if (node.parent == NODE_OFFSET_INVALID || node.type == parse_special_type_parse_error) { // A root node. prettify_node_recursive(src, parse_tree, i, 0, symbol_job_list, &has_new_line, &result, do_indent); } } return result; }
static void prettify_node_recursive(const wcstring &source, const parse_node_tree_t &tree, node_offset_t node_idx, indent_t node_indent, parse_token_type_t parent_type, bool *has_new_line, wcstring *out_result, bool do_indent) { const parse_node_t &node = tree.at(node_idx); const parse_token_type_t node_type = node.type; /* Increment the indent if we are either a root job_list, or root case_item_list, or in an if or while header (#1665) */ const bool is_root_job_list = (node_type == symbol_job_list && parent_type != symbol_job_list); const bool is_root_case_item_list = (node_type == symbol_case_item_list && parent_type != symbol_case_item_list); const bool is_if_while_header = ((node_type == symbol_job || node_type == symbol_andor_job_list) && (parent_type == symbol_if_clause || parent_type == symbol_while_header)); if (is_root_job_list || is_root_case_item_list || is_if_while_header) { node_indent += 1; } /* Handle comments, which come before the text */ if (node.has_comments()) { const parse_node_tree_t::parse_node_list_t comment_nodes = tree.comment_nodes_for_node(node); for (size_t i=0; i < comment_nodes.size(); i++) { const parse_node_t &comment_node = *comment_nodes.at(i); append_whitespace(node_indent, do_indent, *has_new_line, out_result); out_result->append(source, comment_node.source_start, comment_node.source_length); } } if (node_type == parse_token_type_end) { /* Newline */ out_result->push_back(L'\n'); *has_new_line = true; } else if ((node_type >= FIRST_PARSE_TOKEN_TYPE && node_type <= LAST_PARSE_TOKEN_TYPE) || node_type == parse_special_type_parse_error) { if (node.has_source()) { /* Some type representing a particular token */ append_whitespace(node_indent, do_indent, *has_new_line, out_result); out_result->append(source, node.source_start, node.source_length); *has_new_line = false; } } /* Recurse to all our children */ for (node_offset_t idx = 0; idx < node.child_count; idx++) { /* Note we pass our type to our child, which becomes its parent node type */ prettify_node_recursive(source, tree, node.child_start + idx, node_indent, node_type, has_new_line, out_result, do_indent); } }
/* Entry point for prettification. */ static wcstring prettify(const wcstring &src, bool do_indent) { parse_node_tree_t tree; if (! parse_tree_from_string(src, parse_flag_continue_after_error | parse_flag_include_comments | parse_flag_leave_unterminated | parse_flag_show_blank_lines, &tree, NULL /* errors */)) { /* We return the initial string on failure */ return src; } /* We may have a forest of disconnected trees on a parse failure. We have to handle all nodes that have no parent, and all parse errors. */ bool has_new_line = true; wcstring result; for (node_offset_t i=0; i < tree.size(); i++) { const parse_node_t &node = tree.at(i); if (node.parent == NODE_OFFSET_INVALID || node.type == parse_special_type_parse_error) { /* A root node */ prettify_node_recursive(src, tree, i, 0, symbol_job_list, &has_new_line, &result, do_indent); } } return result; }
static void prettify_node_recursive(const wcstring &source, const parse_node_tree_t &tree, node_offset_t node_idx, indent_t node_indent, parse_token_type_t parent_type, bool *has_new_line, wcstring *out_result, bool do_indent) { const parse_node_t &node = tree.at(node_idx); const parse_token_type_t node_type = node.type; const parse_token_type_t prev_node_type = node_idx > 0 ? tree.at(node_idx - 1).type : token_type_invalid; // Increment the indent if we are either a root job_list, or root case_item_list, or in an if or // while header (#1665). const bool is_root_job_list = node_type == symbol_job_list && parent_type != symbol_job_list; const bool is_root_case_list = node_type == symbol_case_item_list && parent_type != symbol_case_item_list; const bool is_if_while_header = (node_type == symbol_job_conjunction || node_type == symbol_andor_job_list) && (parent_type == symbol_if_clause || parent_type == symbol_while_header); if (is_root_job_list || is_root_case_list || is_if_while_header) { node_indent += 1; } if (dump_parse_tree) dump_node(node_indent, node, source); if (node.has_comments()) // handle comments, which come before the text { auto comment_nodes = tree.comment_nodes_for_node(node); for (const auto &comment : comment_nodes) { append_whitespace(node_indent, do_indent, *has_new_line, out_result); auto source_range = comment.source_range(); out_result->append(source, source_range->start, source_range->length); } } if (node_type == parse_token_type_end) { out_result->push_back(L'\n'); *has_new_line = true; } else if ((node_type >= FIRST_PARSE_TOKEN_TYPE && node_type <= LAST_PARSE_TOKEN_TYPE) || node_type == parse_special_type_parse_error) { if (node.keyword != parse_keyword_none) { append_whitespace(node_indent, do_indent, *has_new_line, out_result); out_result->append(keyword_description(node.keyword)); *has_new_line = false; } else if (node.has_source()) { // Some type representing a particular token. if (prev_node_type != parse_token_type_redirection) { append_whitespace(node_indent, do_indent, *has_new_line, out_result); } out_result->append(source, node.source_start, node.source_length); *has_new_line = false; } } // Recurse to all our children. for (node_offset_t idx = 0; idx < node.child_count; idx++) { // Note: We pass our type to our child, which becomes its parent node type. // Note: While node.child_start could be -1 (NODE_OFFSET_INVALID) the addition is safe // because we won't execute this call in that case since node.child_count should be zero. prettify_node_recursive(source, tree, node.child_start + idx, node_indent, node_type, has_new_line, out_result, do_indent); } }