diff options
Diffstat (limited to 'prism/templates/src/prettyprint.c.erb')
-rw-r--r-- | prism/templates/src/prettyprint.c.erb | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/prism/templates/src/prettyprint.c.erb b/prism/templates/src/prettyprint.c.erb new file mode 100644 index 0000000000..27f44cd996 --- /dev/null +++ b/prism/templates/src/prettyprint.c.erb @@ -0,0 +1,167 @@ +<%# 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.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); + <%- node.fields.each_with_index do |field, index| -%> + <%- preadd = index == node.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::FlagsField -%> + bool found = false; + <%- found = flags.find { |flag| flag.name == field.kind }.tap { |found| raise "Expected to find #{field.kind}" unless found } -%> + <%- found.values.each do |value| -%> + if (cast->base.<%= field.name %> & PM_<%= found.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 |