// Dump a parse tree node in a form helpful to someone debugging the behavior of this program. static void dump_node(indent_t node_indent, const parse_node_t &node, const wcstring &source) { wchar_t nextc = L' '; wchar_t prevc = L' '; wcstring source_txt = L""; if (node.source_start != SOURCE_OFFSET_INVALID && node.source_length != SOURCE_OFFSET_INVALID) { int nextc_idx = node.source_start + node.source_length; if ((size_t)nextc_idx < source.size()) { nextc = source[node.source_start + node.source_length]; } if (node.source_start > 0) prevc = source[node.source_start - 1]; source_txt = source.substr(node.source_start, node.source_length); } wchar_t prevc_str[4] = {prevc, 0, 0, 0}; wchar_t nextc_str[4] = {nextc, 0, 0, 0}; if (prevc < L' ') { prevc_str[0] = L'\\'; prevc_str[1] = L'c'; prevc_str[2] = prevc + '@'; } if (nextc < L' ') { nextc_str[0] = L'\\'; nextc_str[1] = L'c'; nextc_str[2] = nextc + '@'; } fwprintf(stderr, L"{off %4u, len %4u, indent %2u, kw %ls, %ls} [%ls|%ls|%ls]\n", node.source_start, node.source_length, node_indent, keyword_description(node.keyword), token_type_description(node.type), prevc_str, source_txt.c_str(), nextc_str); }
// Dump a parse tree node in a form helpful to someone debugging the behavior of this program. static void dump_node(indent_t node_indent, const parse_node_t &node, const wcstring &source) { int nextc_idx = node.source_start + node.source_length; wchar_t prevc = node.source_start > 0 ? source[node.source_start - 1] : L' '; wchar_t nextc = nextc_idx < source.size() ? source[nextc_idx] : L' '; wchar_t prevc_str[4] = {prevc, 0, 0, 0}; wchar_t nextc_str[4] = {nextc, 0, 0, 0}; if (prevc < L' ') { prevc_str[0] = L'\\'; prevc_str[1] = L'c'; prevc_str[2] = prevc + '@'; } if (nextc < L' ') { nextc_str[0] = L'\\'; nextc_str[1] = L'c'; nextc_str[2] = nextc + '@'; } fwprintf(stderr, L"{off %4d, len %4d, indent %2u, kw %ls, %ls} [%ls|%ls|%ls]\n", node.source_start, node.source_length, node_indent, keyword_description(node.keyword), token_type_description(node.type), prevc_str, source.substr(node.source_start, node.source_length).c_str(), nextc_str); }
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); } }