summaryrefslogtreecommitdiff
path: root/prism/templates/src/prettyprint.c.erb
diff options
context:
space:
mode:
Diffstat (limited to 'prism/templates/src/prettyprint.c.erb')
-rw-r--r--prism/templates/src/prettyprint.c.erb167
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