<%# encoding: ASCII -%> #include "prism/prettyprint.h" // We optionally support pretty printing nodes. For systems that don't want or // need this functionality, it can be turned off with the // PRISM_EXCLUDE_PRETTYPRINT define. #ifdef PRISM_EXCLUDE_PRETTYPRINT void pm_prettyprint(void) {} #else static inline void prettyprint_location(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_location_t *location) { pm_line_column_t start = pm_newline_list_line_column(&parser->newline_list, location->start, parser->start_line); pm_line_column_t end = pm_newline_list_line_column(&parser->newline_list, location->end, parser->start_line); pm_buffer_append_format(output_buffer, "(%" PRIi32 ",%" PRIu32 ")-(%" PRIi32 ",%" PRIu32 ")", start.line, start.column, end.line, end.column); } static inline void prettyprint_constant(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_constant_id_t constant_id) { pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id); pm_buffer_append_format(output_buffer, ":%.*s", (int) constant->length, constant->start); } static void prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node, pm_buffer_t *prefix_buffer) { switch (PM_NODE_TYPE(node)) { case PM_SCOPE_NODE: // We do not need to print a ScopeNode as it's not part of the AST. return; <%- nodes.each do |node| -%> case <%= node.type %>: { <%- if !node.flags.nil? || node.fields.any? -%> pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node; <%- end -%> pm_buffer_append_string(output_buffer, "@ <%= node.name %> (location: ", <%= node.name.length + 14 %>); prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); <%- (fields = [*node.flags, *node.fields]).each_with_index do |field, index| -%> <%- preadd = index == fields.length - 1 ? " " : "| " -%> // <%= field.name %> { pm_buffer_concat(output_buffer, prefix_buffer); pm_buffer_append_string(output_buffer, "+-- <%= field.name %>:", <%= 4 + field.name.length + 1 %>); <%- case field -%> <%- when Prism::Template::NodeField -%> pm_buffer_append_byte(output_buffer, '\n'); size_t prefix_length = prefix_buffer->length; pm_buffer_append_string(prefix_buffer, "<%= preadd %>", 4); pm_buffer_concat(output_buffer, prefix_buffer); prettyprint_node(output_buffer, parser, (pm_node_t *) cast-><%= field.name %>, prefix_buffer); prefix_buffer->length = prefix_length; <%- when Prism::Template::OptionalNodeField -%> if (cast-><%= field.name %> == NULL) { pm_buffer_append_string(output_buffer, " nil\n", 5); } else { pm_buffer_append_byte(output_buffer, '\n'); size_t prefix_length = prefix_buffer->length; pm_buffer_append_string(prefix_buffer, "<%= preadd %>", 4); pm_buffer_concat(output_buffer, prefix_buffer); prettyprint_node(output_buffer, parser, (pm_node_t *) cast-><%= field.name %>, prefix_buffer); prefix_buffer->length = prefix_length; } <%- when Prism::Template::StringField -%> pm_buffer_append_string(output_buffer, " \"", 2); pm_buffer_append_source(output_buffer, pm_string_source(&cast-><%= field.name %>), pm_string_length(&cast-><%= field.name %>), PM_BUFFER_ESCAPING_RUBY); pm_buffer_append_string(output_buffer, "\"\n", 2); <%- when Prism::Template::NodeListField -%> pm_buffer_append_format(output_buffer, " (length: %lu)\n", (unsigned long) (cast-><%= field.name %>.size)); size_t last_index = cast-><%= field.name %>.size; for (uint32_t index = 0; index < last_index; index++) { size_t prefix_length = prefix_buffer->length; pm_buffer_append_string(prefix_buffer, "<%= preadd %>", 4); pm_buffer_concat(output_buffer, prefix_buffer); pm_buffer_append_string(output_buffer, "+-- ", 4); pm_buffer_append_string(prefix_buffer, (index == last_index - 1) ? " " : "| ", 4); prettyprint_node(output_buffer, parser, (pm_node_t *) cast-><%= field.name %>.nodes[index], prefix_buffer); prefix_buffer->length = prefix_length; } <%- when Prism::Template::ConstantField -%> pm_buffer_append_byte(output_buffer, ' '); prettyprint_constant(output_buffer, parser, cast-><%= field.name %>); pm_buffer_append_byte(output_buffer, '\n'); <%- when Prism::Template::OptionalConstantField -%> if (cast-><%= field.name %> == 0) { pm_buffer_append_string(output_buffer, " nil\n", 5); } else { pm_buffer_append_byte(output_buffer, ' '); prettyprint_constant(output_buffer, parser, cast-><%= field.name %>); pm_buffer_append_byte(output_buffer, '\n'); } <%- when Prism::Template::ConstantListField -%> pm_buffer_append_string(output_buffer, " [", 2); for (uint32_t index = 0; index < cast-><%= field.name %>.size; index++) { if (index != 0) pm_buffer_append_string(output_buffer, ", ", 2); prettyprint_constant(output_buffer, parser, cast-><%= field.name %>.ids[index]); } pm_buffer_append_string(output_buffer, "]\n", 2); <%- when Prism::Template::LocationField -%> pm_location_t *location = &cast-><%= field.name %>; pm_buffer_append_byte(output_buffer, ' '); prettyprint_location(output_buffer, parser, location); pm_buffer_append_string(output_buffer, " = \"", 4); pm_buffer_append_source(output_buffer, location->start, (size_t) (location->end - location->start), PM_BUFFER_ESCAPING_RUBY); pm_buffer_append_string(output_buffer, "\"\n", 2); <%- when Prism::Template::OptionalLocationField -%> pm_location_t *location = &cast-><%= field.name %>; if (location->start == NULL) { pm_buffer_append_string(output_buffer, " nil\n", 5); } else { pm_buffer_append_byte(output_buffer, ' '); prettyprint_location(output_buffer, parser, location); pm_buffer_append_string(output_buffer, " = \"", 4); pm_buffer_append_source(output_buffer, location->start, (size_t) (location->end - location->start), PM_BUFFER_ESCAPING_RUBY); pm_buffer_append_string(output_buffer, "\"\n", 2); } <%- when Prism::Template::UInt8Field -%> pm_buffer_append_format(output_buffer, " %" PRIu8 "\n", cast-><%= field.name %>); <%- when Prism::Template::UInt32Field -%> pm_buffer_append_format(output_buffer, " %" PRIu32 "\n", cast-><%= field.name %>); <%- when Prism::Template::Flags -%> bool found = false; <%- field.values.each do |value| -%> if (cast->base.flags & PM_<%= field.human.upcase %>_<%= value.name %>) { if (found) pm_buffer_append_byte(output_buffer, ','); pm_buffer_append_string(output_buffer, " <%= value.name.downcase %>", <%= value.name.bytesize + 1 %>); found = true; } <%- end -%> if (!found) pm_buffer_append_string(output_buffer, " nil", 4); pm_buffer_append_byte(output_buffer, '\n'); <%- when Prism::Template::IntegerField -%> const pm_integer_t *integer = &cast-><%= field.name %>; pm_buffer_append_byte(output_buffer, ' '); pm_integer_string(output_buffer, integer); pm_buffer_append_byte(output_buffer, '\n'); <%- when Prism::Template::DoubleField -%> pm_buffer_append_format(output_buffer, " %f\n", cast-><%= field.name %>); <%- else -%> <%- raise -%> <%- end -%> } <%- end -%> break; } <%- end -%> } } /** * Pretty-prints the AST represented by the given node to the given buffer. */ PRISM_EXPORTED_FUNCTION void pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node) { pm_buffer_t prefix_buffer = { 0 }; prettyprint_node(output_buffer, parser, node, &prefix_buffer); pm_buffer_free(&prefix_buffer); } #endif